Klaus Junge: GIF-Dateiformat (1)

0 50

GIF-Dateiformat (1)

Klaus Junge
  1. 0

    GIF-Dateiformat (2)

    Klaus Junge
    1. 0
      Cheatah
      1. 0
        m0b
        1. 0
          m0b
          1. 0
            Cheatah
          2. 0
            Stefan Muenz
            1. 0
              Cheatah
    2. 0
      Cheatah
      1. 0
        Klaus Junge
        1. 0
          Klaus Junge
          1. 0
            Cheatah
            1. 0
              Klaus Junge
              1. 0
                Cheatah
    3. 0

      GIF-Dateiformat (2a)

      Klaus Junge
      1. 0
        Cheatah
        1. 0
          Klaus Junge
          1. 0
            Cheatah
            1. 0
              Klaus Junge
              1. 0
                Cheatah
              2. 0
                Calocybe
                1. 0
                  Cheatah
                  1. 0
                    Calocybe
                    1. 0
                      Cheatah
                      1. 0
                        Calocybe
        2. 0
          Jörk Behrends
  2. 0
    Olaf Grönemann
  3. 0

    GIF-Dateiformat (k1)

    Klaus Junge
    1. 0

      GIF-Dateiformat (k2)

      Klaus Junge
      1. 0
        Cheatah
        1. 0
          Klaus Junge
          1. 0
            Cheatah
      2. 0

        GIF-Dateiformat (k3)

        Klaus Junge
        1. 0
          Cheatah
        2. 0

          GIF-Dateiformat (k4)

          Klaus Junge
  4. 0

    GIF-Dateiformat (3=Palette)

    Klaus Junge
    1. 0
      Cheatah
      1. 0
        Klaus Junge
        1. 0
          Cheatah
  5. 0

    Aktueller Stand der Dinge

    Cheatah
    1. 0
      Klaus Junge
      1. 0
        Cheatah
      2. 0
        Calocybe
        1. 0
          Cheatah
  6. 0

    GIF-Dateiformat (test_1)

    Klaus Junge
    1. 0
      Cheatah
      1. 0
        Klaus Junge
        1. 0
          Klaus Junge
          1. 0
            Calocybe
          2. 0
            Cheatah

Hallo Cheatah,

hab mal etwas in den 3 GIF-Texten geschmökert.
Laß uns mal Schritt für Schritt herangehen.

Eine GIF-Datei fängt immer mit einer Signatur an.

GIF SIGNATURE:
G I F 8 7 a
G I F 8 9 a

Die Interpretation ist unterschiedlich, einige
betrachten sie als aus 6 Byte besthend, andere
teilen sie auf in GIF und 87a bzw. 89a.
Für Dich ist das zunächst unerheblich, solange
Du Dateien nur baust.
Beim Lesen könnte es sicherer sein wenn Du
tatsächlich erstmal nach GIF schaust und dann erst
nach einem Unterformat.
Auf jeden Fall sind diese ersten 6 Bytes so
festgelegt.

Danach kommen diverse Blocks und das Ende der
Datei ist immer definiert durch:

GIF TERMINATOR = 0x3B hex or ';'

Ob dieses Byte in der Datei nicht vorkommen darf
ist mir zunächst noch nicht klar, kommt
hoffentlich noch.

So, das war erstmal das Alpha und Omega,
demnächst weiter in diesem Kino.

Klaus

  1. Hallo Cheatah,

    so nun kommt der SCREEN DESCRIPTOR Block dran:

    GENERAL FILE FORMAT

    +-----------------------+
      | +-------------------+ |
      | |   GIF Signature   | |
      | +-------------------+ |
      | +-------------------+ |
      | | Screen Descriptor | |
      | +-------------------+ |
      | +-------------------+ |
      | | Global Color Map  | |
      | +-------------------+ |
      . . .       . . .

    "SCREEN DESCRIPTOR
      The Screen Descriptor describes the overall parameters for all  GIF
       images  following.  It defines the overall dimensions of the image space
       or logical screen required, the existance of color mapping  information,
       background  screen color, and color depth information.  This information
       is stored in a series of 8-bit bytes as described below."

    bits
       7 6 5 4 3 2 1 0  Byte #
      +---------------+
      |               |  1
      +-Screen Width -+      Raster width in pixels (LSB first)
      |               |  2
      +---------------+
      |               |  3
      +-Screen Height-+      Raster height in pixels (LSB first)
      |               |  4
      +-+-----+-+-----+      M = 1, Global color map follows Descriptor
      |M|  cr |0|pixel|  5   cr+1 = # bits of color resolution
      +-+-----+-+-----+      pixel+1 = # bits/pixel in image
      |   background  |  6   background=Color index of screen background
      +---------------+      (color is defined from the Global color
      |0 0 0 0 0 0 0 0|  7   map or default map if none specified)
      +---------------+

    Dieser SCREEN DESCRIPTOR - Bereich besteht also aus 7 Byte.
    Die ersten 4 Byte sind wortweise definiert nach Intelnotation,
    also niederwertiger Teil zuerst, dann höherwertiger Teil.
    Wenn Du daraus einen Zeiger machen willst, mußt Du umschaufeln
    und anpassen. Wert = Byte2 * 256 + Byte1.
    Diese beiden 16-bit-Werte beschreiben die Bildschirmgröße
    für die Deine Graphik ausgelegt ist. HTML erlaubt Dir ja eine
    übergeordnete Skalierung mit WIDTH und HEIGHT, diese haben dann
    Vorrang, sonst sollten Browser sich nach diesen Werten richten.
    Die in Browsern eingebauten Skalierungsmechanismen sind jedoch
    ein Dauerthema in diesem Forum.

    Nun kommt SCREEN DESCRIPTOR.Byte_5.

    Dieses Byte ist bitweise auszuwerten.
    Bit_7 beschreibt ob eine globale Palette Verwendung findet
    oder ob das später Bild für Bild gemacht werden soll.
    In Deinem Fall wirst Du Deine Palette also wohl global setzen
    wollen. Sie wird dann unmittelbar hinter dem SCREEN DESCRIPTOR
    Block stehen und M=1.

    Bit_6..4 cr+1 = # bits of color resolution, verstehe ich als Anzahl der
    Farben die für die Darstellung verwendet werden sollen.
    Das hab' ich noch nicht klar drauf und muß noch nachlesen.

    Bit_3 scheint immer leer zu sein.

    Bit_2..0 pixel+1 = # bits/pixel in image, verstehe ich als Farbtiefenangabe,
    also wie die Palette aufgebaut ist. Üblicherweise werden es wohl
    3 Byte pro Farbe sein (=24 bit):
    "The  number  of  color  map  entries  following  a  Screen
    Descriptor  is equal to 2**(# bits per pixel), where each entry consists
    of three byte values representing the relative intensities of red, green
    and blue respectively."
    Zum Bauen von GIFs reicht das wohl erstmal, beim Lesen muß man da wohl
    noch ein paar Varianten klar haben, 16 bit etc...

    Danach kommt SCREEN DESCRIPTOR.Byte_6.
    Dieses ist ein Index (Zeiger) auf die Palette und beschreibt welche
    der Farben für den Hintergrund verwendet werden soll.
    Auch das ist mir bei GIF87a nicht ganz klar, könnte aber mit der
    Kompression zusammenhängen. Bei GIF89a könnte das dann der Wert
    für durchsichtige Bereiche werden.

    SCREEN DESCRIPTOR.Byte_7 ist wohl immer leer und 0.

    So, das war Teil 2...
    Mein armer armer Hosenboden!
    Frag nach wenn was nicht klar ist,
    mir ist aber auch noch nicht alles klar.
    Kriegen wir hoffentlich noch hin.
    Korrekturen und Zurechtweisungen höchst erwünscht!

    Klaus

    1. Hi Klaus,

      danke für die vielen Mühen, ich hab das erst mal ausgedruckt... :-)

      Cheatah

      1. Ich hab eure Beiträge gerade mal schnell gelesen,
        und bin mir Sicher, dass man diese Probleme
        auch leichter in den Griff bekommt.

        Guckt euch doch mal Matt‚s GraphicCounter an.
        http://www.worldwidemart.com/scripts/counter.shtml

        Vielleicht hilft euch das.
        Sieht auf jeden fall so aus, als hätte Perl
        schon irgendwelche funktionen oder so etwas!

        1. Guckt euch doch mal Matt‚s GraphicCounter an.
          http://www.worldwidemart.com/scripts/counter.shtml

          Vielleicht hilft euch das.
          Sieht auf jeden fall so aus, als hätte Perl
          schon irgendwelche funktionen oder so etwas!

          Naja, es sieht so aus als gäbe es etwas das
          fly heisst und sone art interface zwischen perl
          und der gd graphic libary darstellt...

          1. Hi,

            Guckt euch doch mal Matt‚s GraphicCounter an.
            http://www.worldwidemart.com/scripts/counter.shtml

            danke! Dieser Counter ist mir zwar schon bekannt (ich werde ihn wohl auch als Vorbild verwenden), aber meine anderen Grafikprobleme löst er leider auch nicht.

            Naja, es sieht so aus als gäbe es etwas das
            fly heisst und sone art interface zwischen perl
            und der gd graphic libary darstellt...

            Ja, scheint so. Ich möchte aber eigentlich keine großen Module verwenden, sondern "nur" die Bytes erstellen, die ich nach STDOUT oder auf den Server schreibe, wo sie dann als GIF interpretiert werden. Dazu müßte es reichen, erst "GIF87a", dann Größenangaben und Farbtabellen und schließlich die Pixel selber (in welcher Form auch immer) zu printen. Ich möchte dies gerne selber machen, nicht nur weil es einfacher ist (nicht so viele Zusatzressourcen braucht), sondern auch weil ich es dann verstehe und leichter modifizieren kann. Ich beginne zwar allmählich, Klaus's Hilfe zu verstehen, aber naja... ganz zu den Geheimnissen vorgedrungen bin ich noch nicht :-)

            In jedem Fall noch mal danke für die Hilfe!

            Cheatah

          2. Hallo m0b

            Naja, es sieht so aus als gäbe es etwas das
            fly heisst und sone art interface zwischen perl
            und der gd graphic libary darstellt...

            Yepp. Das ist ein C-Programm, das sich per Kommandozeile (oder z.B. Perl-Systemaufruf) steuern laesst und aufgrund uebergebener Ziffern GIF-Dateicode mit der entsprechenden Zahl erzeugt. Da haben wilde Tueftler gegruebelt seinerzeit, bis der erste sichtbare Counter fuer Webseiten geboren war <g>. Und die URL: http://www.unimelb.edu.au/fly/fly.html

            viele Gruesse
              Stefan Muenz

            1. Hi Stefan & m0b,

              Yepp. Das ist ein C-Programm, das sich per Kommandozeile (oder z.B. Perl-Systemaufruf) steuern laesst und aufgrund uebergebener Ziffern GIF-Dateicode mit der entsprechenden Zahl erzeugt. Da haben wilde Tueftler gegruebelt seinerzeit, bis der erste sichtbare Counter fuer Webseiten geboren war <g>. Und die URL: http://www.unimelb.edu.au/fly/fly.html

              danke für diese Info! Ich beginne gerade, den Grundaufbau von GIF87a zu verstehen, vielleicht hilft mir dieses dann noch weiter.

              Cheatah

    2. Hi Klaus,

      +-+-----+-+-----+      M = 1, Global color map follows Descriptor
        |M|  cr |0|pixel|  5   cr+1 = # bits of color resolution
        +-+-----+-+-----+      pixel+1 = # bits/pixel in image

      cr scheint etwa so zu laufen: Farbauflösung aus 2^(3*(cr+1)) Farben, also z.B. cr=%111=7 => 2^(3*8) = 2^24 Farben => Truecolor.
      pixel ist dagegen die Größe der Farbpalette, also pixel=%111=7 => 2^(pixel+1)=2^8=256 Farben in der Palette. Jede dieser Farben wird mit 3*(cr+1) Bit (R/G/B) kodiert.

      |   background  |  6   background=Color index of screen background

      Dies scheint wichtig zu sein, weil der Image Descriptor (ich bin schon weiter *g*) zunächst Position und Größe des Einzelbildes definiert. Das Bild kann nach rechts und unten verschoben sein und durch seine Größe auch unten und rechts noch einen Rand lassen.

      Ich habe mal einen Beispielheader für eine 256-Farben-Grafik (von weiß nach rot in Truecolor) der Größe 320x240 aufgebaut, der bis kurz vor die eigentlichen Pixel geht:

      GIF87a
      $01$40    Breite=320
      $00$F0    Höhe=240
      %11110111 256 Farben Truecolor
      $00       Hintergrundfarbe=Farbe Nr. 0
      $00       Trennzeichen
      $FFFFFF   weiß (erste Farbe)
      ...
      $FF0000   rot (256. Farbe)
      %00101100 Image Seperator (",")
      $00$00    linker Rand
      $00$00    oberer Rand
      $01$40    Breite Einzelbild
      $00$F0    Höhe Einzelbild
      %00000000 non-interlaced mit globaler Farbpalette

      Jetzt muß ich mich erst mal schlau machen, ob (ich glaube ja) die lokale Farbpalette einfach entfällt, und wie ich dann das eigentliche Bild aufbaue. Wäre aber nett, wenn Du mit Deinen Erkenntnissen noch mal nachschauen würdest, ob das bisher alles so stimmt!

      Cheatah

      1. Hi Cheatah,

        ob (ich glaube ja) die lokale Farbpalette einfach entfällt...

        Glaube ich bislang auch, da Du ja sagst:

        %11110111 256 Farben Truecolor

        ----* = global palette

        ich schau aber nochmal nach, bin noch nicht soweit.

        Du gehst ja ran wie sonstwas, prima-gut!

        Klaus

        1. Hi Cheatah,

          ob (ich glaube ja) die lokale Farbpalette einfach entfällt...

          Glaube ich bislang auch, ...

          jahh, in GIF89a.txt steht:

          21. Local Color Table.

          a. Description. This block contains a color table, which is a sequence of
               bytes representing red-green-blue color triplets. The Local Color Table
               is used by the image that immediately follows. Its presence is marked by
               the Local Color Table Flag being set to 1 in the Image Descriptor; if
               present, the Local Color Table immediately follows the Image Descriptor
               and contains a number of bytes equal to
                                    3x2^(Size of Local Color Table+1).

          If present,
               ==========

          this color table temporarily becomes the active color table
               and the following image should be processed using it. This block is
               OPTIONAL; at most one Local Color Table may be present per Image
               Descriptor and its scope is the single image associated with the Image
               Descriptor that precedes it.

          Wenn vorhanden dann..., ergo braucht sie das nicht zu sein!

          Klaus

          1. Hi Klaus,

            Wenn vorhanden dann..., ergo braucht sie das nicht zu sein!

            ja, danke, zu der Erkenntnis bin ich auch gerade gekommen :-)
            Ich versuche derzeit, irgendwie ein einfaches GIF per Perl zurückzuliefern, aber das klappt leider nicht... es gibt einfach nur einen Internal Server Error :(((

            Cheatah

            1. Hi Cheatah,

              Ich versuche derzeit, irgendwie ein einfaches GIF per Perl zurückzuliefern, aber das klappt leider nicht... es gibt einfach nur einen Internal Server Error :(((

              und wie ist das mit der Kompression?
              ich hab's noch nicht drauf!
              Kannst ja erstmal ein vorhandenes Muster reinpacken.

              Der Server Error hat damit aber wohl nichts zu
              tun, der kann das ja wohl nicht merken, auch wenn
              das Bild erstmal kokolores zeigt.
              Server dürften sich wohl eher über offene Dateien
              oder sowas beschweren.
              Oder kommt die Fehlermeldung aus der Anwendung
              bzw dem Browser zurück?

              Klaus

              1. Hi Klaus,

                Oder kommt die Fehlermeldung aus der Anwendung
                bzw dem Browser zurück?

                nein, das kommt schon vom Server (heißt ja auch Internal SERVER Error :-) ). Ich denke auch, daß im allerschlimmsten Fall der Browser abstürzt, eher aber nur Blödsinn angezeigt wird. Es wird also irgendetwas mit dem Script zu tun haben.

                Cheatah

    3. Hallo Cheatah,

      war mit den vorhergehenden Sachen wohl noch nicht ganz durch.

      Der Text zu GIF89a ist wohl doch um ein Vielfaches präziser.

      Zu HEADER

      hier wird die Signatur explizit auf 'GIF' begrenzt.
      Der String '87a' oder '89a' wird benutzt um der verarbeitenden
      Anwendung mitzuteilen welche Fähigkeiten sie aufweisen muß.
      Kann eine Anwendung eine 89a-Datei nicht verarbeiten, so
      sollte sie eine Fehlermeldung ausgeben.
      Wenn Du also auch Bilder einlesen willst, dann solltest Du
      besser GIF89a 'können'.

      HINWEIS: der HEADER muß vorhanden sein, und zwar genau 1mal.

      BEACHTE, in den Tabellen sind die Zählweisen geändert,
      sie beginnen jetzt mit 0!

      7 6 5 4 3 2 1 0        Field Name   Type
           +---------------+
         0 |               | 'G'   Signature    3 Bytes
           +-             -+
         1 |               | 'I'
           +-             -+
         2 |               | 'F'
           +---------------+
         3 |               | '8'   Version      3 Bytes
           +-             -+
         4 |               | '7' oder '9'
           +-             -+
         5 |               | 'a'
           +---------------+

      zu LOGICAL SCREEN DESCRIPTOR.

      7 6 5 4 3 2 1 0        Field Name                    Type
           +---------------+
        0  |               |       Logical Screen Width          Unsigned
           +-             -+
        1  |               |
           +---------------+
        2  |               |       Logical Screen Height         Unsigned
           +-             -+
        3  |               |
           +---------------+
        4  | |     | |     |       <Packed Fields>               See below
           +---------------+
        5  |               |       Background Color Index        Byte
           +---------------+
        6  |               |       Pixel Aspect Ratio            Byte
           +---------------+

      HINWEIS: der LOGICAL SCREEN DESCRIPTOR muß vorhanden sein,
      und zwar genau 1mal.

      zu Logical Screen Width und Logical Screen Height ist mir nichts
      neues aufgefallen.

      <Packed Fields>  =
            Global Color Table Flag       1 Bit     (M)
            Color Resolution              3 Bits    (cr)
            Sort Flag                     1 Bit     (0)
            Size of Global Color Table    3 Bits    (bits/pixel)

      hier sind nun alle bits belegt.

      GLOBAL COLOR TABLE FLAG (M) wie gehabt, mit dem Zusatz, daß der Inhalt
      des Feldes Background bedeutungslos ist wenn dieses Bit = 0.

      Values :    0 -   No Global Color Table follows, the Background
                        Color Index field is meaningless.
                  1 -   A Global Color Table will immediately follow, the
                        Background Color Index field is meaningful.

      COLOR RESOLUTION  (cr) Erklärung präziser. Dieses Feld hat 3 bit,
      womit ein maximaler Wert von 8 angegeben werden kann, also 8 bit
      pro RGB-Farbe und Pixel.
      Damit können dann maximal 24bit-Farben definiert werden (256 aus...).

      Color Resolution - Number of bits per primary color available
      to the original image, minus 1. This value represents the size of
      the entire palette from which the colors in the graphic were
      selected, not the number of colors actually used in the graphic.
      For example, if the value in this field is 3, then the palette of
      the original image had 4 bits per primary color available to create
      the image.  This value should be set to indicate the richness of
      the original palette, even if not every color from the whole
      palette is available on the source machine.

      SORT FLAG (0) ist neu, war vorher null. Dieses Bit oder Flag gibt
      an ob die Palette (wohl nach Häufigkeit) sortiert ist oder nicht.

      v) Sort Flag - Indicates whether the Global Color Table is sorted.
      If the flag is set, the Global Color Table is sorted, in order of
      decreasing importance. Typically, the order would be decreasing
      frequency, with most frequent color first. This assists a decoder,
      with fewer available colors, in choosing the best subset of colors;
      the decoder may use an initial segment of the table to render the
      graphic.

      Values :    0 -   Not ordered.
                  1 -   Ordered by decreasing importance, most
                        important color first.

      SIZE OF GLOBAL COLOR TABLE (bits/pixel) Erklärung besser.
      Dieser Wert hoch 2 genommen gibt die Länge der globalen
      Palette an. 2 hoch 8 ergibt 256, wodurch die Palette also maximal
      256 Einträge bekommen kann. Die Palette kann aber wiederum
      aus 24bit-Werten bestehen, was besagte 16Mio Farben ergeben könnte.
      Das hier beschriebene Prinzip ermöglicht also eine Auswahl
      von 256 Farben aus 16Mio. Das kommt einem doch bekannt vor, oder?

      Size of Global Color Table - If the Global Color Table Flag is
      set to 1, the value in this field is used to calculate the number
      of bytes contained in the Global Color Table. To determine that
      actual size of the color table, raise 2 to [the value of the field

      • 1].  Even if there is no Global Color Table specified, set this
        field according to the above formula so that decoders can choose
        the best graphics mode to display the stream in.  (This field is
        made up of the 3 least significant bits of the byte.)

      BACKGROUND COLOR INDEX  Erklärung besser.
      Für HTML eigentlich bedeutungslos da dabei der Hintergrund, der
      Bereich um das Bild herum anders bestimmt wird.

      Index into the Global Color Table for
      the Background Color. The Background Color is the color used for
      those pixels on the screen that are not covered by an image. If the
      Global Color Table Flag is set to (zero), this field should be zero
      and should be ignored.

      PIXEL ASPECT RATIO neu, war vorher auf null. Gibt das Seitenverhältnis
      einzelner Pixel an. Solltest Du auf vermutlich lieber null halten.
      Mir ist nicht klar inwieweit diese Information mit den Setitenver-
      hältnissen des Bildes zusammenspielen muß. Gesetzt den Fall Du hast
      oben 100*100 Pixel gesagt und hier steht 4, wie soll Dein Bild werden?
      Ist es dann 400*100 oder 100*400?

      Pixel Aspect Ratio - Factor used to compute an approximation
      of the aspect ratio of the pixel in the original image.  If the
      value of the field is not 0, this approximation of the aspect ratio
      is computed based on the formula:

      Aspect Ratio = (Pixel Aspect Ratio + 15) / 64

      The Pixel Aspect Ratio is defined to be the quotient of the pixel's
      width over its height.  The value range in this field allows
      specification of the widest pixel of 4:1 to the tallest pixel of
      1:4 in increments of 1/64th.

      Values :        0 -   No aspect ratio information is given.
                 1..255 -   Value used in the computation.

      Weiter sind wir eigentlich noch nicht, aber ein paar Sachen werden
      mir langsam etwas klarer, Dir auch?
      Die Unterschiede zwischen 87a und 89a scheinen mir bislang nicht so
      gravierend zu sein als daß man sich deswegen auf 87a beschränken sollte.

      Klaus

      PS: da scheint ja einiger Traffic zu sein und Du scheinst auch langsam
      Blut zu lecken. Unabhängig davon ob es schon was gibt, sollten wir
      uns da langsam mal durchfressen. Was ich von Deinen Überlegungen auf
      die Schnelle so gesehen habe scheint ok zu sein. Gucke es mir aber erst
      später genauer an.

      1. Hi Klaus,

        BEACHTE, in den Tabellen sind die Zählweisen geändert,
        sie beginnen jetzt mit 0!

        da sich die GIF89a-Spezifikation nur durch wenige Bits von der GIF87a-Spezi zu unterscheiden scheint, wäre mir das gar nicht so aufgefallen... ich beschränke mich erst mal auf 87a, und später werde ich wohl einiges wiedererkennen :-)

        +---------------+
          6  |               |       Pixel Aspect Ratio            Byte
             +---------------+
        Gesetzt den Fall Du hast
        oben 100*100 Pixel gesagt und hier steht 4, wie soll Dein Bild werden?
        Ist es dann 400*100 oder 100*400?

        Mir scheint, das ist nur interessant, wenn es ohnehin schon 400*100 ist... warum ist mir allerdings schleierhaft. Jedenfalls heißt:

        The Pixel Aspect Ratio is defined to be the quotient of the pixel's
        width over its height.

        "Breite / Höhe = Pixel Aspect Ratio"

        Weiter sind wir eigentlich noch nicht, aber ein paar Sachen werden
        mir langsam etwas klarer, Dir auch?

        Ja, der Groschen fällt - zwar pfennigweise, aber er fällt :-)

        PS: da scheint ja einiger Traffic zu sein und Du scheinst auch langsam
        Blut zu lecken. Unabhängig davon ob es schon was gibt, sollten wir
        uns da langsam mal durchfressen. Was ich von Deinen Überlegungen auf
        die Schnelle so gesehen habe scheint ok zu sein. Gucke es mir aber erst
        später genauer an.

        Oki!

        Übrigens: Wie binde ich eigentlich GD.pm ein? Ich habe jetzt einige Varianten von use GD; versucht, aber ohne Erfolg. Ich weiß nicht mal, ob es auf dem Server liegt! "whereis GD[.pm]" brachte jedenfalls keinen Erfolg. Wie installiere ich es im Zweifelsfall?

        Cheatah

        1. Hi Cheatah,

          "Breite / Höhe = Pixel Aspect Ratio"

          aber das gilt nur pro Pixel.

          Ja, der Groschen fällt - zwar pfennigweise, aber er fällt :-)

          Hältst Du Dich denn für'n Heiamannfresser?

          Übrigens: Wie binde ich eigentlich GD.pm ein?

          keinen blassen schimmer, bin PERLanalphabet!

          Klaus

          1. Hi,

            "Breite / Höhe = Pixel Aspect Ratio"
            aber das gilt nur pro Pixel.

            ganz klar ist es mir trotzdem nicht...

            Ja, der Groschen fällt - zwar pfennigweise, aber er fällt :-)
            Hältst Du Dich denn für'n Heiamannfresser?

            Eigentlich nicht :-)

            Übrigens: Wie binde ich eigentlich GD.pm ein?
            keinen blassen schimmer, bin PERLanalphabet!

            Schade! Weiß jemand anders bescheid?

            Cheatah

            1. Hi Cheatah,

              "Breite / Höhe = Pixel Aspect Ratio"

              ganz klar ist es mir trotzdem nicht...

              die Absicht hab' ich auch noch nicht kapiert,
              im Moment tendiere ich dazu, das als Korrektur-
              möglichkeit für die Darstellungsverhältnisse zu
              betrachten.

              600/800 = 0,75
              800/1024 = 0,78...

              Die Differenz ist zwar nicht groß, korrekt läßt
              sich das Bild aber nicht bei beiden Auflösungen
              unverzerrt darstellen. Dieses ist umso wahrer
              wenn Du von einem auf den anderen Bildschirm
              gehst.

              Wenn Du das beim Bau des Bildes korrekt
              verzeichnet hast, dann kannst Du das beim zweiten
              Bildschirm ausgleichen.

              Drucker haben ja auch nicht immer gleiche Auflösungen.

              Ist halt nur so'n Gedanke.

              Klaus

              1. Hi Klaus,

                hm... das ist natürlich möglich. Naja, die Leute werden sich schon irgendetwas dabei gedacht haben, aber im Moment reicht mir das 87a-Format eigentlich :-)

                Cheatah

              2. Hallo! Lese gerade Euren Dialog. Mmh, naja, mir persoenlich bringt's nicht viel, da ich die gif-spec selbst schon mal zu lesen angefangen habe, aber fuer die anderen ist sicherlich interessant.
                Zu diesem Posting will ich aber kurz was korrigieren:

                600/800 = 0,75
                800/1024 = 0,78...

                Die Differenz ist zwar nicht groß, korrekt läßt sich das Bild aber nicht bei beiden Auflösungen
                unverzerrt darstellen. Dieses ist umso wahrer  wenn Du von einem auf den anderen Bildschirm gehst.

                Die zweite Aufloesung heisst doch nicht 1024x800, sondern 1024x768. Und dann isses auch wieder 0.75. Die meisten Aufloesungen im PC-Bereich haben das Seitenverhaeltnis (=aspect ratio) von Breite:Hoehe = 4:3. Nur 320x200 tanzt da aus der Reihe. Naja, die Erfinder von GIF haben sicher auch (bzw. hauptsaechlich) an andere Plattformen gedacht. Z.B. gab's da beim Amiga mal eine Aufloesung von 320x256.

                Wenn Du jetzt ein Bild fuer die PC-Standardverhaeltnisse bauen willst, dann muss imho eine Aspect ratio von 1 (= 0 im Feld Pixel Aspect Ratio) verwendet werden. Die Ausmasse des Bildschirms sind zwar in der Breite groesser, als in der Hoehe (jetzt mal in cm), aber dafuer werden da auch entsprechend mehr Pixel dargestellt. Letztendlich heisst das, dass die Pixel quadratisch sein muessen, also aspect ratio = 1 (width:heigt = 1:1). Um beim Beispiel vom Amiga zu bleiben: Das Seitenverhaeltnis bezogen auf die Groesse des Bildschirms ist dort auch 4:3 (weil ein herkoemmlicher Bildschirm nunmal diese Ausmasse hat), das Verhaeltnis der dargestellten Pixel waere aber 320:256 = 5:4. Das muss ausgeglichen werden. Sagen wir der einfachkeit halber, der Bildschirm ist 400mm x 300mm gross, dann ist jeder Pixel 400mm:320 = 1.25mm breit und 300mm:256 = 1.171875mm hoch. Damit haben wir eine aspect ratio von 1.25:1.17 = 1.06667. Das ist das, was bei der Formel
                Aspect Ratio = (Pixel Aspect Ratio + 15) / 64
                auf der linken Seite herauskommen muss. ("Pixel Aspect Ratio" ist der Name des Feldes im Screen descriptor, "Aspect Ratio" ist das Seitenverhaeltnis des Pixels, wie er auf dem Bildschirm gemalt wird, wenn ich das richtig verstanden habe (verwirrend, was?).) Der Wert, den man in das Feld schreiben muesste, waere demnach
                PixelAspectRatio = 1.06667 * 64 - 15 = 53. Jetzt weiss ich nur nicht, was man machen muss, wenn man das Bild anzeigt und auf so einen Wert trifft. Aber ich glaube, herkoemmliche Bildbetrachter ignorieren diesen Wert, wodurch z.B. ein Bild, das fuer 320x200 entwickelt wurde, auf einer 4:3-Aufloesung ziemlich dumm aussieht.
                Das alles, wie gesagt: IMHO. (Hoffentlich habt ihr jetzt nicht das Thema GIF aufgegeben ;-))

                Und die Praxis? Einfach 0 an diese Stelle schreiben!

                Calocybe

                1. Hi Calocybe,

                  Deinem Fazit schließe ich mich mal spontan an, zumal ich mich erst mal mit GIF87a beschäftige... und da braucht man diese Ratio nicht mehr bzw. noch nicht. Aber da Du Dich mit dem Thema auszukennen scheinst: Was muß ich machen, um das GIF am Ende anzugeigen? Ich habe sämtliche Header usw. nach bestem Wissen und Gewissen korrekt erstellt, nur muß ich jetzt die Pixel anzeigen... in meinem einfachen Beispiel habe ich 64x32 Pixel mit 256 Farben gewählt. Testweise habe ich 32 Zeilen à 64 Pixel in einer der Zeile zuzuordnenden Farbe ausgeprintet, aber das brachte ruckzuck ein broken image. Was tun, bzw. wie tun?

                  Danke schon mal für die Hilfe!

                  Cheatah

                  1. Hi Calocybe,

                    Aber da Du Dich mit dem Thema auszukennen scheinst: ...

                    Nee, nee, das hab ich nich gesagt. Mit "Mmh, naja, mir persoenlich bringt's nicht viel.." meinte ich nur das was ihr bis zu dem Zeitpunkt diskutiert habt. Weiter hatte ich naemlich auch nicht gelesen, und dann war wiedermal die Zeit zu knapp. Und die Aspect-Ratio-Sache weiss ich auch nur, weil ich sowas mal in der Doku zu PovRay 2.0 gelesen habe. Also sorry, ich kann Euch da auch nicht gross helfen. Aber wenn mir wieder was auffaellt, kann ich ja meinen Senf dazugeben.

                    »»  Testweise habe ich 32 Zeilen à 64 Pixel in einer der Zeile zuzuordnenden Farbe ausgeprintet, aber das brachte ruckzuck ein broken image. Was tun, bzw. wie tun?

                    Na das wird wohl daran liegen, dass Du die Daten einfach als plain Bit-Map rausgeschoben hast, was mit dem GIF-Format nicht so ganz viel zu tun hat. Deshalb hat Dein Bildbetrachter (der hat doch die Fehlermeldung gebracht?) gedacht, dass das Bild auf irgendeinem Transport kaputtgegangen ist.

                    Danke schon mal für die Hilfe!

                    Da *muss* ich dann wohl leider sagen "Nichts zu danken", da ist ja nichts, wofuer Du danken kannst. :(

                    Calocybe

                    1. Hi,

                      ... Also sorry, ich kann Euch da auch nicht gross helfen. Aber wenn mir wieder was auffaellt, kann ich ja meinen Senf dazugeben.

                      schade eigentlich, aber ich freue mich schon mal auf zukünftigen Senf :-)

                      Na das wird wohl daran liegen, dass Du die Daten einfach als plain Bit-Map rausgeschoben hast, was mit dem GIF-Format nicht so ganz viel zu tun hat. Deshalb hat Dein Bildbetrachter (der hat doch die Fehlermeldung gebracht?) gedacht, dass das Bild auf irgendeinem Transport kaputtgegangen ist.

                      Inzwischen bin ich da auch drauf gegangen. Irgendwie habe ich wohl eine Anmerkung falsch verstanden und dachte, daß die Komprimierung optional ist... nach nochmaligem Lesen weiß ich selber nicht, wie ich auf einen so dummen Gedanken kommen konnte :-)
                      Mein Bildbetrachter ist übrigens Netscape, das ist am einfachsten. Online wird das Bild erstellt, online wird es angezeigt!

                      Danke schon mal für die Hilfe!
                      Da *muss* ich dann wohl leider sagen "Nichts zu danken", da ist ja nichts, wofuer Du danken kannst. :(

                      *rotfl* Endlcih ergibt diese Floskel mal einen Sinn!!! :-)))

                      Cheatah

                      1. Hi,

                        Inzwischen bin ich da auch drauf gegangen. Irgendwie habe ich wohl eine Anmerkung falsch verstanden und dachte, daß die Komprimierung optional ist... nach nochmaligem Lesen weiß ich selber nicht, wie ich auf einen so dummen Gedanken kommen konnte :-)

                        Wenn ich mich recht erinnere, habe ich genau das auch gedacht, als ich das das erste Mal gelesen habe. Danke fuer den Hinweis, das erste war naemlich bisher auch mein einziges * (mal).

                        Calocybe

        2. Hi Cheatah!

          Übrigens: Wie binde ich eigentlich GD.pm ein? Ich habe jetzt einige Varianten von use GD; versucht, aber ohne Erfolg. Ich weiß nicht mal, ob es auf dem Server liegt! "whereis GD[.pm]" brachte jedenfalls keinen Erfolg. Wie installiere ich es im Zweifelsfall?

          Cheatah

          In der Regel kann man wohl nicht davon ausgehen, auf einem System GD.pm vorzufinden. Das Paket, das Du Dir inzwischen ja auch schon besorgt hast, beinhaltet zwar GD.pm - jedoch ist
          das nicht alles, was gebraucht wird. GD.pm ist lediglich die Schnittstelle zu einer C-Library, die bei der Installation erst kompiliert wird.

          Wenn Du also auf einem Rechner arbeitest, auf dem Du nur eingeschränkte  Rechte hast (error.log kannst Du z.B. ja nicht lesen), wirst Du selbst wohl auch die Installation nicht durchführen können.

          Generell läuft die Installation eines Perl-Moduls wie folgt ab (vorausgesetz, daß dieses mit MAKEPERL.pl daherkommt):

          perl MAKEPERL.pl
          make test
          make install

          Bei 'make install' werden dann auch die Module in die entsprechenden Verzeichnisse gelegt. GD.pm würde also hierdurch im  ../perl/lib... Verzeichnis landen.

          Gruß,
             Jörk

  2. hi Cheatah, hi Klaus,

    ich darf meinen Vorschlag vom 1. Thread wiederholen?

    Wenn ein fertiges Modul nicht weiterhilft, dann befasst Euch mit einem Grafik Konverter wie die genannten GD Graphics Library oder "netpbm". Das sind Programme, die eine Grafik über stin als Buchstabenfolge, die Pixel beschreiben, einlesen können und als Ausgabe eine fertige GIF-Datei mit Header und komprimierten Daten ausgeben.

    Die GIF-Spec ist ohne weiteres interessant, aber wenn ihr Ergebnisse wollt, dann fangt wie beschrieben an. Könnt ihr erstmal eure Grafiken quasi "unkomprimiert" erzeugen, dann könnt ihr euch ja mit Headern oder Kompressionsalgorithmen befassen und das verbessern.

    Tschuess
    Olaf

  3. Hallo Cheatah,

    da Du ein so'n flinken Jung' bist, sollte ich wohl
    besser erstmal zur Kompression durchstarten, es
    wird die wohl härteste Nuss des ganzen Unterfangens.
    (ob das richtig ist, weiss ich noch nicht)

    Ich nehme mir dazu mal
    GIF-COMP.TXT
    LZW and GIF explained
    von Steve Blackstock vor.

    LZW = Lempel Ziv Welch.

    Dieses Kompressionsverfahren geht zunächst mal davon aus,
    daß in Datenströmen sich wiederholende Muster vorhanden
    sind. Diese müssten sich herausfiltern/kürzen lassen.

    Es wird gesagt, daß das Verarbeitungsverfahren 3 Objekte
    handhaben muß:
    "the charstream, the codestream, and  the string table"

    Bei der Kompression ist der 'charstream' der Input,
    der 'codestream' der Output und die 'string table' eine Art
    temporärer Zwischenzustand. Bei der Dekompression sind
    'charstream' und 'codestream' vertauscht.

    Der erste Schritt ist die Initialisierung der 'string table'.
    Dazu müssen zunächstmal Annahmen gemacht werden.
    Hierzu muß eine Codegröße (Anzahl bits) angenommen werden.
    12 bits ermöglicht/erfordert eine Menge von 0->FFF hex oder
    4096 Einträge in der 'string table'.
    Außerdem es muß bekannt sein wieviel Zustände unsere Daten
    (character) annehmen können. Unter der Annhame, daß sie 32
    Zustände (zB. Farbwerte für jedes Pixel) annehmen können,
    kann die 'string table' wie folgt initialisiert werden.

    code#0  to character#0,
    code#1  to character#1,
    ...
    code#31 to character#31.

    Damit wird definiert, daß jeder 'code' von 0 bis 31
    auf einen Wurzelwert (root) abgebildet wird.
    Es gibt in der Tabelle keine weiteren Einträge mit
    dieser Eigenschaft.

    Nun geht das Komprimieren los.
    Zunächst wird etwas definiert was wir "current prefix" nennen.
    Es ist lediglich ein "prefix" {Variable?} in dem wir Sachen
    speichern können und womit wir auch vergleichen können.
    Wir beziehen uns als "[.c.]" darauf.
    Anfangs ist "current prefix" noch leer.

    Ferner wird noch ein "current string" definiert in dem dieser
    "current prefix" und das nächste Zeichen des Eingangsstroms
    gespeichert werden. Ich beziehe mich auf das "current string"
    als "[.c.]K", wobei K ein Datum des Eingangsstroms ist.
    So, laß uns schauen welches das erste Zeichen des Eingangs-
    stroms ist.
    Nenn es P und der "current string" wird [.c.]P. (zu diesem
    Zeitpunkt ist das natürlich ein 'Wurzelwert'.)
    Laß uns jetzt die "string table" absuchen um zu sehen ob
    [.c.]P enthalten ist. Es ist es, weil unsere "string table"
    derart initialisiert ist, daß jeder mögliche Wurzelwert ent-
    halten ist. In diesem Fall brauchen wir nichts weiter zu machen.

    Nun wird [.c.]P zum "current prefix" gemacht und das nächste
    Zeichen aus dem Eingangsstrom übernommen. Laß es uns Q nennen.
    Dadurch wird "current prefix" zu [.c.]Q {=PQ?}.
    Jetzt wird die "string table" abgesucht um zu sehen ob [.c.]Q
    enthalten ist. Es ist nicht enthalten, also muß etwas getan werden.
    [.c.]Q (=PQ) wird als code#32 in die "string table" eingetragen
    und [.c.] wird im Ausgangsstrom eingetragen.

    Nun geht das Ganze von vorn los, wobei der "current prefix"
    schlicht den Wurzelwert P enthält.

    Füge weiter Zeichen des Eingangsstroms als [.c.]K hinzu, bis
    [.c.]K nicht mehr in der "string table" gefunden werden kann.
    Trage dann [.c.]K in der "string table" ein und im Ausgangs-
    strom ein.

    In Pseudocode ausgedrückt:

    [1] Initialize string table;
    [2] [.c.] <- empty;
    [3] K <- next character in charstream;
    [4] Is [.c.]K in string table?
      (yes: [.c.] <- [.c.]K;
            go to [3];
      )
      (no: add [.c.]K to the string table;
           output the code for [.c.] to the codestream;
           [.c.] <- K;
           go to [3];
      )

    It's as simple as that! So einfach ist das! {oder?}

    Natürlich, wenn Du zu [3] zurückkommst und im Eingangsstrom
    keine Zeichen mehr sind, dann schreibst Du den code für [.c.]
    in den Ausgangsstrom und bist fertig.
    Du kannst die Tabelle nun wegschmeissen.

    Cheatah, hast Du's verstanden? Ich noch nicht.

    Es kommt jetzt ein Beispiel, aber erst demnächst in diesem Kino.

    Bei GIF-Daten können maximal 256 Zustände (8bit Palette) auf-
    treten und ein Datenblock darf doch nur 256 Byte lang werden.
    Dieses ist aber der Ausgangsstrom.
    Wie lang muß die Tabelle werden?
    Vielleicht kommt's ja noch.
    Die obige Beschreibung bezieht sich auf standard LZW-Kompression,
    GIF-LZW macht einige zusätzliche Annahmen und kann auch etwas
    vereinfachen.

    Klaus

    1. Hallo Cheatah,

      also weiter, jetzt kommt das Beispiel.

      Laß uns ein 4-Zeichen-Alphabet vorgeben : A,B,C,D.
      Der Eingangsstrom möge ABACABA lauten.

      Laß es uns nun komprimieren.

      Die 'string table' initialisieren wir auf:
      #0=A,  
      #1=B,
      #2=C,
      #3=D.

      Eingangsstrom = ABACABA.
        [.c.]         = -------.
        string table  = A,B,C,D.
        Ausgangsstrom = .

      Das erste Zeichen des Eingangsstroms ist A,
      A ist in der 'string table' enthalten,
      also wird [.c.] zu A. Sonst nichts.

      Eingangsstrom = -BACABA.
        [.c.]         = A------.
        string table  = A,B,C,D.
        Ausgangsstrom = .

      Dann bekommen wir AB, welches nicht in der
      'string table' Tabelle enthalten ist, daher
      schreiben wir #0 (für [.c.]) in den Ausgangs-
      strom und tragen AB als code#4 in die 'string
      table' ein.

      Eingangsstrom = --ACABA.
        [.c.]         = AB-----.
        string table  = A,B,C,D,AB.
        Ausgangsstrom = 0.

      [.c.] wird B und wir holen uns noch A aus dem
      Eingangsstrom und [.c.]A = BA. Es ist nicht
      in der 'string table' enthalten, also schreiben
      wir code#1 in den Ausgangsstrom und tragen
      BA als code#5 in die 'string table' ein.

      Eingangsstrom = ---CABA.
        [.c.]         = -BA----.
        string table  = A,B,C,D,AB,BA.
        Ausgangsstrom = 0,1.

      [.c.] wird zu A und wir holen uns C aus dem
      Eingangsstrom und [.c.]C = AC. Es ist nicht
      in der 'string table' enthalten, also schreiben
      wir code#0 in den Ausgangsstrom und tragen AC
      als code#6 in die 'string table' ein.

      Eingangsstrom = ----ABA.
        [.c.]         = --AC---.
        string table  = A,B,C,D,AB,BA,AC.
        Ausgangsstrom = 0,1,0.

      [.c.] wird nun zu C und wir holen uns A aus dem
      Eingangsstrom und [.c.]A = CA. Es ist nicht
      in der 'string table' enthalten, also schreiben
      wir code#2 für C in den Ausgangsstrom und tragen
      CA als code#7 in die 'string table' ein.

      Eingangsstrom = -----ABA.
        [.c.]         = ---CA---.
        string table  = A,B,C,D,AB,BA,AC,CA.
        Ausgangsstrom = 0,1,0,2.

      Nun wird [.c.] zu A und wir holen uns B aus dem
      Eingangsstrom und [.c.]B = AB. Es IST  in der
      'string table' enthalten und wir suchen nach ABA,
      welches nicht in der 'string table' enthalten ist,
      also schreiben wir code#4 für AB in den Ausgangs-
      strom und tragen ABA als code#8 in die 'string
      table' ein.

      Eingangsstrom = ------A.
        [.c.]         = ----AB-.
        string table  = A,B,C,D,AB,BA,AC,CA,ABA.
        Ausgangsstrom = 0,1,0,2,4.

      [.c.] wird zu A und der Eingangsstrom ist leer,
      also schreiben wir einfach code#0 für A in den
      Ausgangsstrom und sind fertig.

      Eingangsstrom = -------.
        [.c.]         = ------A.
        string table  = A,B,C,D,AB,BA,AC,CA,ABA.
        Ausgangsstrom = 0,1,0,2,4,0.

      Cheatah, hast Du es nun kapiert?
      Ich kann mir nun irgendwie vorstellen wie
      sowas abläuft, vielleicht könnte ich mit
      dem obigen Pseudocode auch einen allerersten
      Programmprototypen zusammenbasteln, kapiert
      habe ich aber noch keineswegs.
      Im Moment stolpere ich aber über das ABA
      in der strig table, ich hätte eher angenommen,
      daß die Felder nur max. 2 Zeichen breit werden.

      Für heute (Abend) reicht's.
      Fortsetzung folgt.

      Klaus

      PS: Klar, daß 'fertige Arbeit' in Form von GD.PM
      oder dgl. vermutlich weniger Schwellenangst bedeutet.
      Ob das letzlich, vielleicht auch über mehrere Projekte,
      wirklich weniger Arbeit ist, das mag dahingestellt sein.

      Was mich an der Sache aber am meisten fasziniert, ist,
      daß Cheatah, nach ein paar zaudernden Winkelzügen und
      ziemlicher Verzweiflung (*heul*) nun rangeht 'wie Blücher'.

      Sein erstes Posting:
      .gif erstellen mit Perl von Cheatah, 19.1.99, 15:39 Uhr.
      Heute ist der 21.!

      Er hat wohl so um die 30h gebraucht um ein broken IMG in
      den Browser zu kriegen. Ist schon beachtlich!
      Vielleicht überschätzt er sich noch bzw. unterschätzt
      die Sache. Irgendwie hab' ich das Gefühl, daß er es packen
      wird. Vielleicht dauert es noch 100h oder auch 200h bis
      er wirklich ein unbroken IMG ins Web kriegt, danach
      wird er aber der Crack sein, wird euch schön bunt zeigen
      wie die zeitliche Verteilung von Fragen und Antworten
      hier im Forum ist etc. Und, wir werden dasitzen und staunen.

      Das lohnt seine Mühen doch allemal! Hut ab.

      1. Hi Klaus,

        ich kann nur immer wieder ein dickes DANKE wiederholen :-)

        Also, Du hast schon richtig erkannt, daß die Komprimierung für mich jetzt das größte Problem darstellt. Ich drucke Deine Erklärung und dieses Beispiel (das einleuchtend klingt) erst mal aus und sehe, wie ich damit zurechtkomme... dann sehen wir weiter!

        Übrigens habe ich zwischenzeitlich das Script, das eigentlich ein GIF erstellen soll, umgebastelt, daß ich jetzt einen File-Hexdump habe, auf diese Weise kann ich das Format verschiedener Dateien vergleichen. Aber find mal ein GIF87a im Netz! Naja, so gehen die Programmierwerkzeuge jedenfalls komische Wege...

        Cheatah, hast Du es nun kapiert?

        Ich bemühe mich... aber die Erklärungen aus Deinem vorherigen Posting habe ich noch nicht genau gelesen, so daß ich nur stirntunzelnd nicken kann :-)

        Ich kann mir nun irgendwie vorstellen wie
        sowas abläuft, vielleicht könnte ich mit
        dem obigen Pseudocode auch einen allerersten
        Programmprototypen zusammenbasteln, kapiert
        habe ich aber noch keineswegs.

        Ah ja, ungefähr das :-)

        Vielleicht überschätzt er sich noch bzw. unterschätzt
        die Sache. Irgendwie hab' ich das Gefühl, daß er es packen
        wird. Vielleicht dauert es noch 100h oder auch 200h bis
        er wirklich ein unbroken IMG ins Web kriegt, danach
        wird er aber der Crack sein, wird euch schön bunt zeigen
        wie die zeitliche Verteilung von Fragen und Antworten
        hier im Forum ist etc. Und, wir werden dasitzen und staunen.

        Das lohnt seine Mühen doch allemal! Hut ab.

        Danke für diesen Zuspruch! :-D

        Cheatah

        1. Hallo Cheatah,

          Ich drucke Deine Erklärung und dieses Beispiel ...

          wir sind aber noch nicht durch!
          Komprimierung geht noch weiter.
          Um Deine 'Ungestümheit' zu fördern:
          kannst ja mal schauen ob es Scripte
          gibt wo man wildern kann.

          Aber find mal ein GIF87a im Netz!

          Hast Du zB PSP oder Lview, die können das.
          Damit könntest Du Dir ganz gezielt Testfiles bauen.

          Klaus

          1. Hi,

            wir sind aber noch nicht durch!
            Komprimierung geht noch weiter.

            dachte ich mir :-)

            Um Deine 'Ungestümheit' zu fördern:
            kannst ja mal schauen ob es Scripte
            gibt wo man wildern kann.

            Im Moment erstelle ich gerade einen kleinen GIF-Kurs für Anfänger (wie mich). Wenn man versucht, jemandem etwas beizubringen, lernt man nämlich selbst am meisten!

            Aber find mal ein GIF87a im Netz!
            Hast Du zB PSP oder Lview, die können das.
            Damit könntest Du Dir ganz gezielt Testfiles bauen.

            Schon klar, werde ich bei Bedarf auch tun, aber für's erste war ich dazu zu faul... außerdem wollte ich auch nur meine Ausgabe mit einem bestehenden ähnlichen Beispiel vergleichen :-)
            Es hat immerhin zu dem Ergebnis geführt, daß meine Grafikausgabe korrekt ist. Wenn ich nämlich die Daten eines existierenden Bildes vom Script erzeugen lasse, zeigt der Browser korrekt eine Grafik. Immerhin! Jetzt muß ich nur noch die Daten selber berechnen.

            Cheatah

      2. Hallo Cheatah,

        ich geh' jetzt nochmal an gif-comp.txt ran.

        Ach so, hab Dir faulem Stück noch die Quellen rausgesucht:
        http://www.dcs.ed.ac.uk/%7Emxr/gfx/gif87a.txt
        http://www.dcs.ed.ac.uk/%7Emxr/gfx/gif89a.txt
        http://www.dcs.ed.ac.uk/%7Emxr/gfx/gif-comp.txt
        aber nicht angewöhnen, nachher rostest Du womöglich noch ein.
        Das wollen wir doch garnicht erst einreissen lassen.

        Also nun an der Kompression weiter:

        "
        Ein paar Worte (vier) sollten noch zur Effizienz verloren werden:
        'benutze eine hashing Strategie'. {use a hashing strategy}
        Das Durchsuchen der 'string table' kann rechnertechnisch recht
        aufwendig sein und hashing ist die Mühe wert.
        Beachte auch, daß geradlinige LZW-Kompression die Gefahr beinhaltet
        die 'string table' überlaufen zu lassen. Es kann dann passieren, daß
        man einen 'code' vorfindet/zusammenstellt, der nicht mehr auf die
        Anzahl bits abzubilden geht die für die 'codes' bereitgestellt wurde.
        Es gibt verschiedene Möglichkeiten damit umzugehen und GIF verwendet
        eine besonders clevere, da kommen wir aber noch hin.

        Eine wichtige Sache ist noch zu beachten. Wenn [...]K in der
        'string table' ist, dann ist auch [...] vorhanden. Dieses gilt
        zu jedem beliebigen Zeitpunkt während der Kompression.
        Dieser Umstand legt eine effiziente Methode nahe Strings in der
        Tabelle abzuspeichern. Statt die ganzen Strings von K's abzulegen,
        kann auch folgendes bedacht werden. Jeder String kann als prefix
        plus einem Zeichen betrachtet werden, als [...]K. Wenn man also
        [...]K abspeichern will, weiß man, daß [...] bereits vorhanden ist.
        Daher kann man auch einfach den code für [...] und das Zeichen
        für K ablegen.

        Dieses bezieht sich auf Kompression. Dekompression ist vielleicht
        schwerer zu verstehen, es ist aber wirklich einfacher zu programmieren.
        Wir haben hierbei auch mit einer initialisierten 'string table' anzu-
        fangen. Diese Tabelle leiten wir von unserem Wissen über die Zustände
        ab die wir annehmen unsere Zeichen im Zeichenstrom annehmen können.
        Bei GIF-Dateien steht diese Information im Header, als Anzahl möglicher
        Zustände die unsere Pixel annehmen können. Der Charm von LZW ist, daß
        dieses alles ist was wir zu wissen haben. Den Rest der Tabelle bauen
        wir während der Dekompression auf. Die Kompression ist derart erfolgt,
        daß wir niemals einen code im Codestrom antreffen werden den wir nicht
        in einen String übersetzen könnten.

        Wir müssen etwas "current code" genanntes definieren, das ich als
        "<code>" referenzieren werde. Ausserdem noch einen "old-code" den ich
        als "<old>" referenzieren werde.
        Um anzufangen, laß uns den ersten code untersuchen. Dieses ist jetzt
        <code>. Dieser code wird als Darstellung eines Wurzelwertes in der
        initialisierten Tabelle vorhanden sein. Schreibe diesen Wurzelwert
        in den Ausgangsstrom. Mache dann diesen code zum old-code <old>.
        * Laß uns jetzt den nächsten code untersuchen und ihn zu <code>
        machen. Er wird möglicherweise nicht in der 'string table' vorhanden
        sein, laß uns aber erstmal annehmen, daß er es ist.
        Schreibe den String der dem code entspricht in den Ausgangsstrom.
        Suche nun das erste Zeichen im String den Du gerade übersetzt hast.
        Nenn ihn K. Füge ihn mit dem aus <old> gebildeten prefix [...] zu
        einem neuen String [...]K zusammen. Setze diesen String [...]K in
        die 'string table' und den old-code <old> auf den aktuellen code <code>.
        Wiederhole das Verfahren von dem Punkt an wo ich den Stern '*' gesetzt
        habe und Du hast alles.
        Lies diesen Abschnitt nochmal wenn Du ihn eben nur überflogen hast!!!

        Laß uns die Möglichkeit untersuchen, daß <code> nicht in der 'string
        table' vorhanden ist. Erinnere Dich an die Kompression und versuche
        zu verstehen was geschieht wenn einen String wie P[...]P[...]PQ im
        Eingangsstrom auftaucht. Nimm an, daß P[...] bereits in der 'string
        table' steht, P[...]P aber noch nicht.
        Der Komprimierer wird P[...] erkennen und feststellen, daß P[...]P
        nicht in der 'string table' vorhanden ist. Er wird den code für
        P[...] rausschreiben und P[...]P in die 'string table' einfügen.
        Dann wird er sich für den nächsten String bis P[...]P durcharbeiten
        und herausfinden, daß P[...]P in der Tabelle ist, als der gerade
        hinzugefügte code, also wird er den code für P[...]P ausgeben wenn
        er P[...]PQ nicht in der Tabelle finden kann.
        Der Dekomprimierer hinkt dem Komprimierer immer einen Schritt hinterher.
        Wenn der Dekomprimierer den code für P[...]P sieht, wird er diesen
        code noch nicht in die 'string table' geschrieben haben haben, weil er
        das Anfangszeichen von P[...]P benötigt hätte um den String für den
        letzten code, P[...] zusammenzusetzen und den code für P[...]P zu
        bilden.

        Wie auch immer, wenn ein Dekomprimierer einen code findet den er noch
        nicht kennt, wird es stets derjenige sein, der als nächstes der 'string
        table' hinzugefügt wird.
        So kann er schätzen welches der code sein könnte, und er wird tat-
        sächlich immer richtig liegen.
        Wenn ich ein Dekomprimierer wäre und den code#124 sähe und meine
        'string table' hätte lediglich Einträge bis code#123 hinauf, dann
        könnte ich mir vorstellen was code#124 zu sein hätte, könnte ihn
        der 'string table' hinzufügen und den String ausgeben.
        Wenn code#123 den String generiert hat auf den ich mich hier als [...]
        beziehe, dann wird code#124, in diesem speziellen Fall, [...] plus
        dem ersten Zeichen von [...] sein. Also füge schlicht das erste
        Zeichen von [...] am Ende seinerselbst zu. Nicht schlecht.

        Als (sehr gewöhnliches) Beispiel dieses besonderen Falles, laß uns
        ein Bild voraussetzen bei welchem die ersten drei Pixel die gleiche
        Farbe haben. Mein Datenstrom sieht also etwa so aus: QQQ....
        Zur besseren Übersicht, laß uns meinetwegen annehmen, daß wir 32
        Farben haben und, daß Q die Farbe color#12 ist.
        Der Komprimierer wird die Folge 12,32,... bilden.
        (Wenn du nicht weißt warum, dann denke ein Minütchen darüber nach.)
        Erinnere Dich daran, daß #32 anfänglich nicht in der Tabelle steht,
        da sie nur von #0 bis #31 geht.
        Der Dekomprimierer wird #12 sehen und es richtig in die Farbe Q über-
        setzen. Dann wird er #32 sehen und noch nicht wissen was das heißt.
        Wenn er aber lang genug darüber nachdenkt, kann er sich vorstellen,
        daß QQ der Eintrag #32 in der Tabelle sein müsste und, daß QQ die
        nächste Ausgabe sein sollte.

        Der Pseudocode für die Dekompression sollte also irgendwie so aussehen:

        [1] Initialize string table;
             [2] get first code: <code>;
             [3] output the string for <code> to the charstream;
             [4] <old> = <code>;
             [5] <code> <- next code in codestream;
             [6] does <code> exist in the string table?
              (yes: output the string for <code> to the charstream;
                    [...] <- translation for <old>;
                    K <- first character of translation for <code>;
                    add [...]K to the string table;        <old> <- <code>;  )
              (no: [...] <- translation for <old>;
                   K <- first character of [...];
                   output [...]K to charstream and add it to string table;
                   <old> <- <code>
              )
             [7] go to [5];

        Auch hier gilt, wenn Du zu Schritt [5] zurückkommst und keine codes
        mehr übrig sind, dann bist Du fertig.
        Ausgabe von Strings und das auffinden der Anfangszeichen in Strings
        sind allesamt ein Effizienzproblem, ich werde aber keine Andeutungen
        zu ihrer Lösung machen. Der halbe Spaß an der Programmierung besteht
        aus dem Ausdenken dieser Lösungen.
        "

        So, bin immernoch nicht fertig, aber doch auch rechtschaffen fertig.
        Genug für heute.
        Es kommen noch einige GIF-Spezialitäten. Nicht viel, aber anscheinend
        auch nicht ganz einfach geschrieben. Der Rest dieses Aufsatzes wird
        aber wohl auch noch nicht die endgültige Erleuchtung bringen.
        Ich baue noch auf einige Informationen in den beiden anderen Texten.
        Sollte auch das nicht ausreichen, dann wird die Such in den Algo-
        rithmenbiebeln losgehen.

        Klaus

        1. Hi Klaus,

          Ach so, hab Dir faulem Stück noch die Quellen rausgesucht:
          http://www.dcs.ed.ac.uk/%7Emxr/gfx/gif87a.txt
          http://www.dcs.ed.ac.uk/%7Emxr/gfx/gif89a.txt
          http://www.dcs.ed.ac.uk/%7Emxr/gfx/gif-comp.txt
          aber nicht angewöhnen, nachher rostest Du womöglich noch ein.
          Das wollen wir doch garnicht erst einreissen lassen.

          danke, aber das hätte ich noch selbst hingekriegt... jetzt habe ich nur keine Ausrede mehr *grins* :-)

          Den Text drucke ich gerade aus!

          Cheatah

        2. Hallo Cheatah,

          nun zu den GIF-Variationen diese Themas.

          "
          Im Headerteil einer GIF-Datei, im Raster-Data-stream, gibt es ein
          'code size' genanntes Feld. Ein unglücklicher Name für dieses Feld,
          wir müssen aber damit leben. In Wirklichkeit ist es die Grundgröße,
          die 'root size'.
          Die tatsächliche Anzahl der 'compression  codes' in bits schwankt
          während der Kompression/Dekompression und ich werde die Größe
          "compression size" nennen.
          Die Tabelle enthält anfänglich, wie üblich alle Wurzelwerte der codes,
          aber oben werden noch zwei spezielle codes angefügt. Nimm an, Du hast
          eine code-Größe ("code  size") die üblicherweise der Anzahl der Bits
          pro Pixel im Bild entspricht, also N. Wenn die Anzahl der Bits/Pixel
          eins ist, dann muß N gleich 2 sein: die Wurzelwerte belegen die
          Plätze #0 und #1 der anfänglichen Tabelle und die beiden speziellen
          codes belegen die Plätze #4 und #5.
          In jedem anderen Fall, ist N die Anzahl von Pixeln pro Byte, die
          Wurzelwerte belegen die Plätze #0 bis #(2**N-1) und diese beiden
          speziellen codes (2**N) und (2**N + 1). Die anfängliche Größe der
          Kompressionscodes wird N+1 bits pro code betragen.
          Wenn Du am Komprimieren bist, gibst Du die codes jeweils (N+1) bitweise
          aus und wenn Du am Dekodieren bist holst Du Dir jeweils (N+1) bits aus
          dem Eingangstrom.

          Nun zu den beiden speziellen codes: <CC> oder 'clear code' ist (2**N)
          und <EOI> oder 'end of information' ist (2**N+1).
          <CC> sagt dem Kompressor, daß die 'String table' neu aufzubauen ist
          und, daß die 'compression size' auf (N+1) zurückzusetzen ist.
          <EOI> bedeutet, daß nichts mehr im 'codestraem' vorhanden ist.

          Wenn Du am Kodieren oder Dekodieren bist, solltest Du Sachen die der
          'string table' hinzuzufügen sind ab <CC>+2 einsetzen.
          Wenn Du am Kodieren bist, solltest Du <CC> als allerersten code aus-
          geben und danach immer wenn Du code #4095 (hex FFF) erreichst, da GIF
          keine 'compression sizes' erlaubt die größer als 12 bits sind.

          Wenn Du am Dekodieren bist, solltest Du Deine 'string table' neu
          initialisieren wann immer Du <CC> siehst. Die variablen 'compression
          sizes' sind wahrlich keine besondere Aufgabe.

          Wenn Du am Kodieren bist, fängst Du mit einer 'compression size' von
          (N+1) bit an, und, wann immer Du den code (2**(compression size)-1)
          ausgibst haust Du die 'compression size' um ein bit hoch. So wird
          der nächste code den Du ausgibst um ein Bit länger. Denk aber daran,
          daß die längste 'compression size' 12 bits ist, was einem code von
          4095 enstpricht. Wenn Du so weit gekommen bist, mußt Du <CC> als
          nächsten code ausgeben und neu aufsetzen {and start over}.

          Wenn Du dekodierst, mußt Du die 'compression size' erhöhen SOBALD Du
          #(2**(compression size) - 1) in die 'string table' schreibst.
          Der nächste code den Du LIEST, wird ein bit länger sein.
          Mach nicht den Fehler mit dem Hinzufügen des codes (2**compression
          size) zu warten. Du wirst dann schon ein bit des vorhergehenden codes
          verloren haben.

          Das Packen der codes in den Datenstrom der raster data ist auch ein
          potentieller Stolperstein für den Anfänger.
          Das niederwertigste Bit im code sollte mit dem niedrigsten verfügbaren
          bit im ersten erreichbaren byte im codestream übereinstimmen.
          Als Beispiel, wenn Du mit 5-bit compression  codes anfängst, und Deine
          ersten drei codes <abcde>, <fghij>, <klmno>, sind, wobei e, j, und o
          bit#0 darstellen, dann sollte Dein codestream lauten:

          byte#0: hijabcde
                 byte#1: .klmnofg

          Also, der Unterschied zwischen reinem LZW und GIF-LZW ist:

          zwei zusätzliche spezielle codes und
            variable   compression sizes.

          Wenn Du also LZW verstehst und diese Unterschiede auch, dann verstehst
          Du alles!

          Nur als eine Art P.S., Du magst bemerkt haben, daß ein Komprimierer
          ein klein wenig spielraum beim Komprimieren hat. Ich hab einen
          'gierigen' Ansatz für die Kompression beschrieben indem ich soviel
          Eingangszeichen wie möglich zusammengeklaubt habe bevor ich ein code
          ausgegeben habe. Dieses ist tatsächlich die übliche LZW-Art Sachen zu
          machen, und, dieses wird die besten Kompressionsergebnisse ergeben.
          Aber, es gibt keine Regel die besagt, daß Du nicht irgendwo zwischen-
          durch aufhören kannst um ein code für ein Prefix auszugeben, egal ob
          es in der Tabelle steht oder nicht, und dann erst den String und das
          nächste Zeichen in die 'string table' zu setzen. Es gibt verschiedene
          Gründe das so tun zu wollen, besonders wenn die Strings besonders lang
          werden und hashing schwierig machen. Wenn Du es für erforderlich hältst,
          dann tu es.
          "

          Soweit dieser letzte Teil.
          Weißt Du nun was böhmische Dörfer sind?
          Ich glaub ich weiß auch das nicht mehr.
          Ich bin immer mehr dazu übergegangen nur noch zu übersetzen,
          wohl vor allem weil ich nicht mehr mitkam.
          Ich werde mir das Ganze nochmal vornehmen.
          Ein paar Randbedingungen sind ja doch noch rübergekommen,
          aber den Algorithmus zu implementieren würde ich mich noch nicht trauen.

          Klaus

          PS: mal sehen ob das was wird, mein Proxy hat
          andauernd behauptet, daß Stefans Server down ist
          ERROR (57). 2 blue screens hatte ich auch noch.

  4. Hallo Cheatah,

    nur mal kurz zwischendurch das Kapitel Palette aus GIF89a.TXT.
    Du hast das wohl schon intus, der Vollständigkeit halber aber doch noch.

    19. Global Color Table.

    a. Description. This block contains a color table, which is a sequence of
          bytes representing red-green-blue color triplets. The Global Color Table
          is used by images without a Local Color Table and by Plain Text
          Extensions. Its presence is marked by the Global Color Table Flag being
          set to 1 in the Logical Screen Descriptor; if present, it immediately
          follows the Logical Screen Descriptor and contains a number of bytes
          equal to
                        3 x 2^(Size of Global Color Table+1).

    This block is OPTIONAL; at most one Global Color Table may be present
          per Data Stream.

    Das ist also eine einfache byteorientierte Tabelle, bestehend aus RGB-Triplets.
    Wer auch nur ein wenig HTML drauf hat, beherrscht somit die Definitionsgrundlagen.
    Diese Tabelle darf nur vorhanden sein wenn das Bit oben im Descriptor gesetzt ist,
    oder umgekehrt, wenn die Tabelle vorhanden ist, muß das Bit gesetz sein (+ Größe).

    GLOBAL COLOR TABLE FLAG BEING SET TO 1 IN THE LOGICAL SCREEN DESCRIPTOR

    Die Tabelle kann und darf maximal einmal vorhanden sein (also 0..1 mal).

    Außerdem ist es unbedingt erforderlich die richtige Größe im
    LOGICAL SCREEN DESCRIPTOR = 3 x 2^(Size of Global Color Table+1)
    in jenem <Packed Fields>-Feld Bits_2..0 einzutragen.

    Die Palette muß, wenn vorhanden unmittelbar hinter dem
    LOGICAL SCREEN DESCRIPTOR untergebracht sein.

    Den Aspekt Plain Text vernachlässige ich mal geflissentlich; für den
    Bau von GIFs zunächst unwesentlich, fürs Einlesen vielleicht doch.

    b. Required Version.  87a

    c. Syntax.

    7 6 5 4 3 2 1 0        Field Name                    Type
             +===============+
          0  |               |       Red 0                         Byte
             +-             -+
          1  |               |       Green 0                       Byte
             +-             -+
          2  |               |       Blue 0                        Byte
             +-             -+
          3  |               |       Red 1                         Byte
             +-             -+
             |               |       Green 1                       Byte
             +-             -+
         up  |               |
             +-   . . . .   -+       ...
         to  |               |
             +-             -+
             |               |       Green 255                     Byte
             +-             -+
        767  |               |       Blue 255                      Byte
             +===============+

    d. Extensions and Scope. The scope of this block is the entire Data
          Stream. This block cannot be modified by any extension.

    e. Recommendation. None.

    Dieses Thema ist also kurz und trivial.

    Klaus

    1. Hi Klaus,

      nur mal kurz zwischendurch das Kapitel Palette aus GIF89a.TXT.
      Du hast das wohl schon intus, der Vollständigkeit halber aber doch noch.

      jepp, völlig richtig :-)

      Übrigens, mal so nebenbei - wir arbeiten ja parallel an der Lösung, wie Du sicherlich gemerkt hast. Das liegt daran, daß ich über die selbe Spezifikation verfüge wie Du, allerdings beschränke ich mich erst mal nur auf 87a. Du brauchst also nicht alles zu kopieren, sondern nur die Passagen, die in 89a anders sind - und natürlich Deine Erkenntnisse! Die bringen mich nämlich meisten am ehesten weiter ;-)

      Und noch mal danke!

      Cheatah

      1. Hi Cheatah,

        Übrigens, mal so nebenbei - wir arbeiten ja parallel an der Lösung, wie Du sicherlich gemerkt hast.

        »»
        Klar, hältst Du mich denn für voll auf den Keks geplumpst?

        Ich hoffe, wir kriegen das gebacken,
        jeder auf seine Weise.

        Klaus

        1. Hi Klaus,

          Klar, hältst Du mich denn für voll auf den Keks geplumpst?

          *lol* das hab ich ja noch nie gehört! *rotfl* Klingt echt genial!!! :-)))
          Aber nein, halte ich nicht. Außerdem, wer plumpst schon gerne auf seine cookies.txt? ;-)

          Ich hoffe, wir kriegen das gebacken,
          jeder auf seine Weise.

          Jepp, da bin ich sicher! Mit gegenseitiger Hilfe sowieso!

          Cheatah

  5. Hi Klaus,

    ich mach mal kurz ein Update:

    Unter http://cheatah.net/cgi-bin/hexdump.pl habe ich einen einfachen Hexdump erstellt. Ohne Parameter wird der Versuch, ein GIF zu erzeugen, ausgedumpt (tolles Wort), mit file= kannst Du ein spezielles File ausdumpen (noch toller :-) ), z.B. http://cheatah.net/cgi-bin/hexdump.pl?file=http://cheatah.net/grf/invisible.gif. Mein momentaner Versuch ist übrigens mit diesem invisible.gif identisch (1x1 transparent), später wird man dort von mir definierte GIFs finden. Mit dem Parameter mode=gif kannst Du eine Ausgabe als GIF erzwingen.

    Mein GIF-Kurs, bzw. soweit ich halt bin, ist unter http://cheatah.net/gifkurs.htm zu finden. Dort werde ich meine Erkenntnisse regelmäßig updaten, also schau gelegentlich mal rein. Momentan steht "nur" das Konzept, es wäre nett wenn Du mal überprüfen könntest - und mir vor allem sagst, was für GIF89a noch dazukommen muß (da bist Du ja der Experte; ich hab die paar Dinge jetzt aus dem Gedächtnis eingefügt).

    Mit der Komprimierung komme ich immer noch nicht klar, aber ich arbeite dran.

    Cheatah

    1. Hallo Cheatah,

      bin gerade auf http://cheatah.net/gifkurs.htm.
      Du machst ja gleich was brauchbares daraus, prima!

      Aber laß mich auch gleich mal etwas rummeckern, ist halt leichter.

      ----------

      Gib die Quellen an, macht sich besser, also:
      GIF87a.TXT aus http://www...
      GIF89a.TXT aus http://www...
      etc.

      ----------

      GIF Signatur      GIF87a bzw.
                        GIF89a             6 Bytes   Erkennungssymbol für das Format

      trenn das auf in 2*3 Byte und 'GIF' + '87a' | '89a'
      ist von der logischen Struktur besser zu packen.

      ----------

      Screen Descriptor Screen Width      2 Bytes  Breite des Gesamtbildes ($HHLL)
                        Screen Height     2 Bytes  Höhe des Gesamtbildes ($HHLL)

      ist das wirklich ($HHLL)? mir war so als ob ich was von Intelnotation gelesen hätte
      und die wäre dann doch ($LLHH).

      ----------

      An ein paar Formulierungen würde ich gerne noch rumfeilen wollen,
      kommt aber erst später, muß mir dazu wohl noch einiges reinziehen.
      Den Dump schaue ich mir nachher genauer an.

      ----------
      zurück ins Forum:

      (da bist Du ja der Experte;...

      dieses Schimpfwort ist doch noch durch nichts gerechtfertigt!
      Nimm es besser zurück.

      Du kannst 'n alten Mann ja ganz schön durch die Gegend hetzen. ;-)

      Klaus

      1. Hi,

        Du machst ja gleich was brauchbares daraus, prima!

        ich tu mein bestes :-) Und wie gesagt, so lernt man am meisten!

        Gib die Quellen an, macht sich besser, also:
        GIF87a.TXT aus http://www...
        GIF89a.TXT aus http://www...

        Gute Idee, werde ich tun! Im Moment bin ich zu faul, die Adressen zu suchen, aber das hole ich noch nach.

        trenn das auf in 2*3 Byte und 'GIF' + '87a' | '89a'
        ist von der logischen Struktur besser zu packen.

        Done!

        ist das wirklich ($HHLL)? mir war so als ob ich was von Intelnotation gelesen hätte
        und die wäre dann doch ($LLHH).

        Ja, stimmt, war ein Gewohnheitsfehler - und copy&paste hat den Rest erledigt... :-)
        Ist korrigiert, danke für den Hinweis!

        An ein paar Formulierungen würde ich gerne noch rumfeilen wollen,
        kommt aber erst später, muß mir dazu wohl noch einiges reinziehen.
        Den Dump schaue ich mir nachher genauer an.

        Alles klar!

        zurück ins Forum:

        (da bist Du ja der Experte;...
        dieses Schimpfwort ist doch noch durch nichts gerechtfertigt!
        Nimm es besser zurück.

        Sorry! Gemeint war, daß Du Dich mit 89a wesentlich mehr beschäftigt hast als ich und ergo auch besser auskennst.

        Du kannst 'n alten Mann ja ganz schön durch die Gegend hetzen. ;-)

        *grins* So kriegst Du auf jeden Fall etwas (geistige) Bewegung! Das hält fit :-)

        Cheatah


      2. Screen Descriptor Screen Width      2 Bytes  Breite des Gesamtbildes ($HHLL)
                          Screen Height     2 Bytes  Höhe des Gesamtbildes ($HHLL)

        ist das wirklich ($HHLL)? mir war so als ob ich was von Intelnotation gelesen hätte
        und die wäre dann doch ($LLHH).


        VORSICHT! Die Notation, wie Cheatah sie benutzt, ist die Pascal-Schreibweise fuer Hex-Zahlen (in C ist es 0xHHLL). HH bedeuten dabei die beiden hoeherwertigen Ziffern (High-Byte), LL die niederwertigen (Low-Byte); na das weisst Du sicher. Es ist richtig, das HH vorn hinzuschreiben, denn "hoeherwertig" bedeutet ja, das es groessere Bedeutung fuer den Gesamtwert der Zahl hat. Und jetzt sag mir mal, welche Ziffer fuer den Gesamtwert der dezimalen Zahl 42 die groessere Bedeutung hat? Die 4! Deshalb steht sie vorn, auf dem Papier jedenfalls, auch auf dem elektronischen Papier. Und das ist immer so, egal ob Intel- oder sonstwas -Notation.

        Jetzt zur Intel-Notation (auch Little Endian Format ganannt). Nehmen wir die Zahl $1234, also $12 * 256 + $34 = 18 * 256 + 52 = 4660. Es gilt HH=$12 und LL=$34. Das Intelformat schreibt nun vor, das niederwertigste Byte an die niederwertigste Speicherstelle zu schreiben (also die Speicherstelle mit der kleinsten Adresse), und das hoechstwertigste Byte an die hoechste Addresse. Adresse ist in diesem Zusammenhang einfach der Offset innerhalb der GIF-Datei.
        Die Zahl $1234 soll nun an der Adresse 0100 stehen (hex oder dec ist erstmal egal). Da die Zahl 2 Bytes gross ist, erstreckt sie sich von 0100 bis 0101. Dabei steht die $34 an 0100 und die $12 an der 0101. Ist doch klar, oder? Naja, wenn man sich sozusagen den Speichern von "unten" nach "oben", durchliest, dann kommt eben die $34 zuerst. Aber genauso gut kann man ihn ja von "oben" nach unten" durchlesen. Auf dem Papier liest man von "vorn" nach "hinten, und ob jetzt "unten" <=> "vorn" und "oben" <=> "hinten" oder umgekehrt, ist mal wieder reine Definitionssache.

        In der GIF-Spec sind die Bilder fuergewoehnlich in dieser Art gemalt:
        Offset    Value
        0100       $34
        0101       $12

        Naja, irgendwie bedeutet "vorn" doch mehr "unten" als "oben", denn die GIF-Datei von "vorn" nach "hinten" gelesen liegt von "unten" nach "oben" im Speicher. Und weil das Format von "vorn" nach "hinten" beschrieben ist, werden die Bilder so gemalt, dass erst die "unteren", dann die "oberen" Adressen kommen. Und deshalb sind die "oberen" Adressen auf dem Papier unten! (Siehe das Bild: die 0100 ist UEBER der 0101, aber im Speicher ist sie drunter.)

        Ach ja, und wenn ein Byte in seine Bits zerlegt wird sieht das meist so aus:
        7 6 5 4 3 2 1 0
        Dabei ist 7 das hoechstwertigste Bit (MSB = most significant bit) und 0 das niederste (LSB = least significant bit). von der Zahl $34 ist die 3 in den Bits 7-4 codiert, die 4 in den Bits 3-0. Diesmal stimmt glaube ich alles mit "vorn" und "hinten".

        Hab ich Euch jetzt total verwirrt? Naja, hoffentlich hat's keiner gelesen, der Thread ist ja schon uralt (einen halben Tag)!  ;-)

        Calocybe

        1. Hi,

          Hab ich Euch jetzt total verwirrt? Naja, hoffentlich hat's keiner gelesen, der Thread ist ja schon uralt (einen halben Tag)!  ;-)

          das nicht ganz, aber fast... :-)
          Wir hatten den Fehler aber schon abgehakt, es war a) Gewohnheit und b) copy&paste... dennoch danke für den Hinweis und natürlich für die technischen Hintergrundinfos!

          Cheatah

  6. Hallo Cheatah,

    zum Testen hab ich mir in PSP (3.11) mal ein Bildchen
    von 16 Pixel Breite und 2 Pixel Höhe in 16 Farben
    gebaut und in GIF87a abgespeichert. Die Farben sind
    in der Reihenfolge der Palette angeordnet.
    Übereinanderliegende Bytes haben gleiche Farben.
    Und so sieht die Datei aus:

    --------  HEADER
    47 49 46  'GIF' = Signature
    38 37 61  '87a' = Version Number

    --------  SCREEN DESCRIPTOR
    10 00     Screen Width
    02 00     Screen Heigth
    B3        1011_0011
                M = 1 = Global Color Map
                cr = 011 = Number of Color Resolution
                0 = %
                pixel = 011
    00        Background Color Index
    00        %

    --------  GLOBAL COLOR MAP
    00 00 00  color#0
    BF 00 00  color#1
    00 BF 00  color#2
    BF BF 00  color#3
    00 00 BF  color#4
    BF 00 BF  color#5
    00 BF BF  color#6
    C0 C0 C0  color#7
    80 80 80  color#8
    FF 00 00  color#9
    00 FF 00  color#10
    FF FF 00  color#11
    00 00 FF  color#12
    FF 00 FF  color#13
    00 FF FF  color#14
    FF FF FF  color#15

    --------  EXTENSION BLOCK
    21        '!' = Extension Block Introducer
    F9        Function Code
    04        Byte Count
    01 00 00  Function Data Bytes
    00        Extension Block Terminator

    --------  IMAGE DESCRIPTOR
    2C        ',' = Image Separator Character
    00 00     Image Left
    00 00     Image Top
    10 00     Image Width
    02 00     Image Height
    00        Flags

    --------  RASTER DATA BLOCK
    04        Code Size
    12        Block Byte Count
    10 04 31  Raster Data
    48 31 07
    25 B5 58
    73 8F 44
    59 98 C6
    79 60 04
    00        Block Terminator
    --------
    3B        ';' = GIF TERMINATOR
    --------

    Der Header ist wie erwartet.

    Beim Screen Descriptor waren aber schon ein paar
    unerwartete Dinge dabei.
    Die Bildbreite und die Höhe sind um ein bit größer
    als ich erwartet hätte. So wie es ist, kannst Du
    theoretisch ein Bild der Größe null definieren.
    Wozu soll das gut sein? PSP läßt nur ab 2*2 zu.
    Der Rest des Screen Descriptors ist wie erwartet.

    Die Global Color Map hat PSP mir gemacht und ent-
    spricht halt 'steinzeitlichen' Farbpaletten wie
    sie dazumal bei CGA-Karten üblich waren.

    Dann kommt unerwartet ein Extension Block.
    Wozu PSP den reinschreibt ist mir nicht klar,
    in der GIF87a-Spezifikation steht zwar, daß er
    existieren kann, das hört sich wie optional an.
    Dann steht aber dabei, daß ein Dekoder den Block
    erkennen und bearbeiten können muß. Wenn er ihn
    nicht verarbeiten kann, dann muß er die Anweisungen
    ignorieren, stolpern darf er jedoch nicht!
    Dieser Block ist nicht komprimiert.
    Eine Erklärung für Function Code hab' ich auf
    die Schnelle nicht gefunden.
    Byte Count sieht mir wie ein Offset auf den
    nächsten Block vor, zeigt in diesem Fall von
    sich selbst auf das letzte Zeichen des Extension
    Blocks, oder wie bei Prozessoren üblich, schon auf
    das erste Zeichen des darauffolgenden Blocks.
    Bei PERL wohl eher der erste Fall.

    Der Image Descriptor fängt, wie spezifiziert mit
    dem Komma an. Die vier Werte für Offset und Größe
    sind wie erwartet.
    Bei den Flags hätte ich aber schon was erwartet (Bit_2..0).
    Bit_7 = M ist null weil es keine Local Color Map gibt.
    Bit_6 = I ist null weil sequentiell = not interlaced.
    Bit_5 = Null weil reserved (oder S wie Sorted).
    Bit_4 = Null weil reserved.
    Bit_3 = Null weil reserved.
    Bit_2..0 = bits/pixel wieso null?
    Zumindest eine 1 hätte ich da erwartet.
    In der 87a-Spezifikation steht was von:
    pixel+1 - # bits per pixel for this image.
    Wenn ich von dem Wert noch einen abziehe,
    dann liege ich wohl voll daneben.
    Also muß es wohl so verstanden werden, daß diesem Wert
    noch eine 1 dazugezählt werden muß um den endgültigen
    Wert zu erhalten. Naja, 'ne Zuweisung steht da nirgends.

    Raster Data Block fängt mit der Code Size an. Das war
    doch die Sache mit der man die 'string table' für die
    Komprimierung aufbaut? Versuch kommt noch.
    Danach kommt das Block Byte Count Byte. Ein Block darf
    also maximal 256 Byte enthalten (komprimierte Bytes!)
    Innerhalb des Raster Data Blocks wiederholen sich dann
    gegebenenfalls Block Byte Count und die Daten.
    Code Size und Terminator sind für ein ganzes Bild gemeinsam.

    GIF Terminator ist wie erwartet.

    --------
    RASTER DATA

    Wenn ich mich nicht furchtbar täusche, sollten die
    unkomprimierten Bilddaten wie folgt lauten:

    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

    Ob's stimmt? Wenn ich das in .BMP abspeichere
    steht es folgendermaßen in der Datei:

    01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF

    Auch logisch bei 4-bit-Farben.
    Auch schon etwas komprimiert, zumindest gepackt.
    Auch wenn ich das als .TIF unkomprimiert abspeichere,
    sehe ich so ein Muster. Hab' ich mich nun getäuscht?

    Wenn ich die Längen vergleiche glaub ich das aber
    wieder nicht. Das .BMP-Muster ist 16 Byte oder 32
    Nibble lang, das komprimierte .GIF-Muster ist 18
    Byte lang und meine erste Annahme ist 32 Byte lang.

    Die komprimierten Daten sollten (laut PSP) so aussehen:

    10 04 31 48 31 07 25 B5 58 73 8F 44 59 98 C6 79 60 04

    Dazwischen liegt nur noch der Kompressionsalgorithmus.
    Mal sehen ob ich Steve Blackstock nachvollziehen kann.

    Das erste was zu machen ist, ist die 'string table'.
    Wie wär's mit:
                                                    <CC><EOI>
    #0 #1 #2 #3 #4 #5 #6 #7 #8 #9 #A #B #C #D #E #F #10  #11
    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  10   11

    Der code für <CC> ist auf 10hex gesetzt. In der Beschreibumg
    steht, daß dieses der erste auszugebende code sein soll.
    In der Tat hat PSP das auch so gemacht.
    Und nun?
    Das erste Eingangszeichen ist 00hex. Das Zeichen existiert
    in der 'string table', [.c.] wird 0, sonst passiert nichts.
    Nun holen wir das nächste Zeichen = 01.
    Damit ist [.c.]K = 0001. Das Zeichen ist nicht in der 'string
    table', wir schreiben eine #0 in den Ausgangastrom und tragen
    0001 in #12 der 'string table' ein.

    Hmmm, irgendwie komme ich damit nicht klar.
    Wenn die eben rausgeschriebene 0 ei Nibble ist, dann ist das
    zwar noch als erster Teil der 04 in Ordnung, aber wie zum
    Teufel soll ich auf die 4 der 04 kommen?

    Da werde ich wohl doch noch mal weiterknobeln und
    schmökern müssen.

    Klaus

    1. Hi Klaus,

      Beim Screen Descriptor waren aber schon ein paar
      unerwartete Dinge dabei.
      Die Bildbreite und die Höhe sind um ein bit größer
      als ich erwartet hätte. So wie es ist, kannst Du
      theoretisch ein Bild der Größe null definieren.

      vielleicht kannst Du die Einzelbilder so definieren, daß sie außerhalb des Gesamtbildes liegen? Das ist vermutlich nur sinnvoll, wenn man eine Hintergrundfarbe mit angibt. Ich glaube da alelrdings nicht dran. Vermutlich ist es so einfacher für den Dekoder.

      Dann kommt unerwartet ein Extension Block.

      Stimmt, das hat mich auch etwas verwirrt... zumal ich 89a bisher kaum angeblickt habe.

      Dann steht aber dabei, daß ein Dekoder den Block
      erkennen und bearbeiten können muß. Wenn er ihn
      nicht verarbeiten kann, dann muß er die Anweisungen
      ignorieren, stolpern darf er jedoch nicht!

      Gut zu wissen!

      Bit_2..0 = bits/pixel wieso null?
      Zumindest eine 1 hätte ich da erwartet.
      In der 87a-Spezifikation steht was von:
      pixel+1 - # bits per pixel for this image.
      Wenn ich von dem Wert noch einen abziehe,
      dann liege ich wohl voll daneben.
      Also muß es wohl so verstanden werden, daß diesem Wert
      noch eine 1 dazugezählt werden muß um den endgültigen
      Wert zu erhalten. Naja, 'ne Zuweisung steht da nirgends.

      Das ist in der Tat so zu verstehen, daß Du zu dem gelesenen Wert noch eins hinzuzählen mußt. Nur so läßt sich mit 3 Bit (= maximal 7) 2^8 kodieren. Außerdem würde eine 0 nicht viel Sinn machen, weil Du dann 2^0 = 1 Farbe hättest - also den Hintergrund.

      Raster Data Block fängt mit der Code Size an. Das war
      doch die Sache mit der man die 'string table' für die
      Komprimierung aufbaut? Versuch kommt noch.

      An der Komprimierung knabbere ich auch gerade. Versuche auf Papier waren "erfolgreich", mit anderen Worten ich weiß jetzt, daß es funktioniert und auch wie es arbeitet. Warum es aber eigentlich funktioniert ist mir immer noch nicht ganz klar... ein paar "Aha"-Erlebnisse brauche ich da wohl noch. Letztlich ist das aber auch irrelevant, obwohl ich mich schon bemühe, mein Verständnis zu erweitern.

      Wenn ich mich nicht furchtbar täusche, sollten die
      unkomprimierten Bilddaten wie folgt lauten:

      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

      Vermutlich doch eher so, wie Du es im BMP-Format beschreibst - schließlich werden nur 4 Bit benötigt! Aber egal...

      Hab' ich mich nun getäuscht?

      Vielleicht sagt "Code size" nur, daß die Farben 4-Bit-kodiert sind? Wäre zwar doppelt gemoppelt, aber... wozu braucht man sonst eine "04"?

      Die komprimierten Daten sollten (laut PSP) so aussehen:

      10 04 31 48 31 07 25 B5 58 73 8F 44 59 98 C6 79 60 04

      Dazwischen liegt nur noch der Kompressionsalgorithmus.
      Mal sehen ob ich Steve Blackstock nachvollziehen kann.
      ...
      Da werde ich wohl doch noch mal weiterknobeln und
      schmökern müssen.

      Ich auch... :-)

      Cheatah

      1. Hallo Cheatah,

        den Durchbruch haben wir wohl beide noch nicht,
        Du scheinst aber näher dran zu sein.
        Ob wir weitergekommen sind, mag auch dahingestellt
        sein. Irgendwie hab' ich aber doch das Gefühl
        was zu lernen. Ich schau weiter. Es macht ja doch
        Spass!

        Klaus

        1. Das hättest du alles allerdings auch einfacher haben können:
          <?m=8739&t=1446>

          Korrektur:

          view-source:http://forum.de.selfhtml.org/?m=8739&t=1446

          Jens

          1. Hi Klaus.

            hatte eben noch ne Suchmaschine angeworfen und
            folgenden Artikel gefunden:

            LZW compression used to encode/decode a GIF file by Bob Montgomery [73357,3140]

            Ne URL waere keine schlechte Idee gewesen. Dann koennte man sich auch das GIFENCOD.GIF holen, auf das im Text verwiesen wird. Und ist das die vollstaendige Kopie des Textes? (Hab noch nicht durchgelesen, will ich mir fuer spaeter aufheben, aber da macht es sich halt gut, wenn man die Quellen kennt.)

            Calocybe

          2. Hi Klaus,

            Hab' ihn noch nicht durchgearbeiet, sieht aber
            irgendwie detailreicher aus.

            ist auf jeden Fall keine "simple" (= komplizierte) technische Spezifikation :-)

            Danke dafür, ich drucke es gerade aus und werde es anschließend durcharbeiten. Mal sehen, was es für Erkenntnisse bringt! Ansonsten stimme ich Calocybe zu: Hast Du die URL noch parat?

            Cheatah