Klaus Junge: zu GIF-Dateiformat

Hallo Cheatah, Calocybe, ...

hatte ich übersehen, bin Euch noch diese Links schuldig.

Auf
http://www1.lu.se/msdosftp/graphics/gif/giftools/gif-doc
finden sich:

compress.gif
gif-doc.zip
gif.doc
gif89a.doc
gifdecod.gif
gifencod.gif

Auf
http://src.doc.ic.ac.uk/public/public/public/packages/dos/collections/simtel/msdos/gif/00_index.txt
gibt es wohl 2 Dutzend Sachen mit 'gif'...

Ansonsten ist mir zwar etwas dazwischen gekommen,
bin aber noch (eher erfolglos) am Knobeln.

Klaus

  1. Hi Klaus,

    danke für die Links! Da gibt's wohl wieder allerhand zu lesen...

    Ansonsten ist mir zwar etwas dazwischen gekommen,
    bin aber noch (eher erfolglos) am Knobeln.

    Wir alle, Klaus, wir alle ;-)

    Cheatah

    1. Hi Klaus,

      danke für die Links! Da gibt's wohl wieder allerhand zu lesen...

      Ansonsten ist mir zwar etwas dazwischen gekommen,
      bin aber noch (eher erfolglos) am Knobeln.

      Wir alle, Klaus, wir alle ;-)

      Hängt es denn bei Euch nur noch an der Komprimierung, oder wo steht Ihr gerade. Könnt ja sein, daß ich mal Lust bekomme eine LZV Funktion zu schreiben ;-)

      Jörk

      1. Hallo Jörk,

        Hängt es denn bei Euch nur noch an der Komprimierung, ...

        nur?! Klar doch, da aber mehr am Verständnis.
        Ansonsten bin ich persönlich totaler PERLanalphabet (noch??).

        Könnt ja sein, daß ich mal Lust bekomme eine LZW Funktion zu schreiben ;-)

        Wäre super, weiß aber auch nicht wie weit Cheatah ist.
        Mir geht es ja mehr ums Verstehen des Verfahrens.

        Klaus

        1. Hallo Klaus!

          Hallo Jörk,

          Hängt es denn bei Euch nur noch an der Komprimierung, ...

          nur?! Klar doch, da aber mehr am Verständnis.

          Mit dem "nur" wollte ich ja zum Ausdruck bringen, daß GIF auch ohne Komprimierung schon einiges zu bieten hat ;-). Auch der Umstand, daß ab einer gewissen Größe die Daten in mehrere Blöcke aufzuteilen sind ... Da darf dann wohl auch die Komprimierung drunter leiden.

          Könnt ja sein, daß ich mal Lust bekomme eine LZW Funktion zu schreiben ;-)

          Wäre super, weiß aber auch nicht wie weit Cheatah ist.
          Mir geht es ja mehr ums Verstehen des Verfahrens.

          Da hatte ich bislang so das Gefühl, daß Du Dich da schon ganz gut eingefuchst hast ... Zumindest warst Du ja derjenige, der das Verfahren hier mit Beispielen vorgeführt hat. Soweit ich mir das ganze angeschaut habe, scheint es eigentlich ganz logisch zu funktionieren. Die Tücken liegen dann allerdings in der Sonderbehandlungen, die im GIF-Format vorkommen können (<CC> und so). Auch daß hier variable Bit-Längen verwendet werden ...

          Jörk

          1. Hallo Jörk,

            Mit dem "nur" wollte ich ja zum Ausdruck bringen, daß GIF auch ohne Komprimierung schon einiges zu bieten hat ;-).

            nicht daß ich wüßte! Hab nirgends was darüber gefunden. Kompression in den Datenblöcken ist wohl zwingend, in den Descriptoren nicht vorgesehen.

            »»  Auch der Umstand, daß ab einer gewissen Größe die Daten in mehrere Blöcke aufzuteilen sind ...

            Die Blöcke sind zwingend, der Längenindex ist nur
            ein Byte groß!

            Da darf dann wohl auch die Komprimierung drunter leiden.

            Da weißt Du wohl mehr als ich!? Eher nein.

            ...der das Verfahren hier mit Beispielen vorgeführt hat.

            Eine Test-Datei analysiert, das Verfahren hab ich
            noch nicht drauf.

            Soweit ich mir das ganze angeschaut habe, scheint es eigentlich ganz logisch zu funktionieren.

            Ist richtig, aber ein paar Groschen müssen noch fallen. Cheatah hat mir auch Hirntraining ver-
            ordnet, gegen Kalkrost oder sowas.

            Die Tücken liegen dann allerdings in der Sonderbehandlungen, die im GIF-Format vorkommen können (<CC> und so).

            Wahrscheinlich weniger, sind Teil des Verfahrens.

            Auch daß hier variable Bit-Längen verwendet werden ...

            Gehört zum (bislang unverstandenen) Kompressionsverfahren.

            Hier noch ein Link und einen Hinweis:

            http://ftp.tu-clausthal.de/pub/TEXT/msdos/graphics/formats

            NUR HINWEIS (auch GIF):
            Graphics: Specifications - These files are only available on the
            Programmers Heaven CD-ROM and they can't be downloaded!
            Graphics fileformats & Protocol Specifications 3D2_FORM.ZIP
            Stereo CAD 2.0 communications pipeline specs 3DDXF.ZIP
            Minimum requirements for creating a DXF.

            http://www.programmersheaven.com/pheaven/www/area17.htm

            Klaus

            1. Klaus!

              Mit dem "nur" wollte ich ja zum Ausdruck bringen, daß GIF auch ohne Komprimierung schon einiges zu bieten hat ;-).

              nicht daß ich wüßte! Hab nirgends was darüber gefunden. Kompression in den Datenblöcken ist wohl zwingend, in den Descriptoren nicht vorgesehen.

              Falscher Hals! Ich meinte das drumherum. Farbtabellen und dergleichen. Aber da seit ihr ja eigentlich mit durch ...

              »»  Auch der Umstand, daß ab einer gewissen Größe die Daten in mehrere Blöcke aufzuteilen sind ...

              Die Blöcke sind zwingend, der Längenindex ist nur
              ein Byte groß!

              Da darf dann wohl auch die Komprimierung drunter leiden.

              Da weißt Du wohl mehr als ich!? Eher nein.

              Ich habe auch schon festgestellt, daß die Kodierung nur einmal auf alles angesetzt wird. Anschließend werden dann die Blöcke mit jeweils höchstens 255 Bytes ausgegeben ... Ich hatte schon befürchtet, daß für jedes Teilstück die Kodierung neu anzusetzen ist ...

              Soweit ich mir das ganze angeschaut habe, scheint es eigentlich ganz logisch zu funktionieren.

              Ist richtig, aber ein paar Groschen müssen noch fallen. Cheatah hat mir auch Hirntraining ver-
              ordnet, gegen Kalkrost oder sowas.

              Ich hoffe, mein anderer Beitrag hilft beim Entkalken ;-)

              Die Tücken liegen dann allerdings in der Sonderbehandlungen, die im GIF-Format vorkommen können (<CC> und so).

              Wahrscheinlich weniger, sind Teil des Verfahrens.

              Auch daß hier variable Bit-Längen verwendet werden ...

              Gehört zum (bislang unverstandenen) Kompressionsverfahren.

              Ich ging jedenfalls davon aus, LZW als solches verstanden zu haben. GIFs arbeiten aber mit einer modifizierten Variante. Diese Änderungen hatte ich noch nicht so ganz verstanden!

              Jörk

          2. So, nochmal Ich!

            Mir geht es ja mehr ums Verstehen des Verfahrens.

            Da hatte ich bislang so das Gefühl, daß Du Dich da schon ganz gut eingefuchst hast ... Zumindest warst Du ja derjenige, der das Verfahren hier mit Beispielen vorgeführt hat. Soweit ich mir das ganze angeschaut habe, scheint es eigentlich ganz logisch zu funktionieren. Die Tücken liegen dann allerdings in der Sonderbehandlungen, die im GIF-Format vorkommen können (<CC> und so). Auch daß hier variable Bit-Längen verwendet werden ...

            Ich habe da mal ein älteres Posting ausgebuddelt, und bin dann doch glatt mit meinem Verständnis gegen die Wand gelaufen:

            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?

            Tja, dachte ich. Der Fehler ist doch offensichtlich: Wenn als Codelänge 4 angegeben ist, dann muß ich doch (erstmal) immer 5 Bits ausgeben (weder 4 noch 8). Klappte aber auch nicht gleich. Dann habe ich aber noch festgestellt, daß man die Bits hier wohl andersherum lesen muß :-).

            Dann kommt alse folgende Starttabelle heraus (niederwertigstes Bit steht links):

            0 - 00000
                1 - 10000
                2 - 01000
                3 - 11000
                4 - 00100
                5 - 10100
                6 - 01100
                7 - 11100
                8 - 00010
                9 - 10010
                A - 01010
                B - 11010
                C - 00110
                D - 10110
                E - 01110
                F - 11110
            <CC> - 00001
            <EOI> - 10001

            Bei der Kodierung der ersten 16 "Zeichen" kommen eigentlich nur die entsprechenden Codes heraus. Erst die zweite Zeile gibt dann bekannte Folgen wieder. Für die erste Zeile bekommen wir dann also sowas wie:
            <CC> 0 1 2 3 4 5 6 7 8 9 A B C D E F
            Binär (wie oben mit fünf Bits)
            00001 00000 10000 01000 11000 00100 10100 01100 11100 00010 10010 01010 11010 00110 10110 01110 11110
            Jetzt in 8er Gruppen:
            00001000 00100000 10001100 00010010 10001100 11100000 10100100 10101101 00011010 11001110 11110xxx
            Die jetzt noch invertiert (höchstwertigstes Bit links)
            00010000 00000100 00110001 01001000 00110001 00000111 00100101 10110101 01011000 01110011 xxx01111
            Und zum Schluß die Nibbles in Hex-Codes
            10 04 31 48 31 07 25 B5 58 73 xF
            Zum Vergleich die PSP-Ausgabe ...
            10 04 31 48 31 07 25 B5 58 73 8F 44 59 98 C6 79 60 04

            :-))))) Jörk

            1. Hallo Ihr zwei!

              Jetzt habe ich auch den Rest hinbekommen. Hier kam die Sache mit der variierenden Code-Länge dazu ...

              Mir geht es ja mehr ums Verstehen des Verfahrens.

              Ich tue mein Bestes :-)

              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

              Bei der Kodierung der ersten 16 "Zeichen" kommen eigentlich nur die entsprechenden Codes heraus. Erst die zweite Zeile gibt dann bekannte Folgen wieder. Für die erste Zeile bekommen wir dann also sowas wie:
              <CC> 0 1 2 3 4 5 6 7 8 9 A B C D E F

              Währenddessen werden noch fleißig weitere Codes generiert:
              01 - 01001
              12 - 11001
              23 - 00101
              34 - 10101
              45 - 01101
              56 - 11101
              67 - 00011
              78 - 10011
              89 - 01011
              9A - 11011
              AB - 00111
              BC - 10111
              CD - 01111
              DE - 11111   <- hier liegt nun der Knackpunkt *)
              EF - 000001

              *) an dieser Stelle ist der 5-stellige Code ausgereizt. Per sofort wird auf 6-stellig umgeschaltet. Das heißt also auch, daß das F aus der ersten Zeile schon 6-stellig ausgegeben wird. Die zweite Zeile wird dann über zweistellige Strings kodiert:
              01 23 45 67 89 AB CD EF

              Nun alles zusammen:
              5stellig: <CC> 0 1 2 3 4 5 6 7 8 9 A B C D E dies sind 16 Codes = 16*5 Bits = 10 Bytes
              => 10 04 31 48 31 07 25 B5 58 73 (siehe vorheriges mailing)

              6stellig:
                 F     01     23     45     67     89     AB     CD     EF    <EOI>
              111100 010010 001010 011010 000110 010110 001110 011110 000010 100010

              = 8stellig:
              11110001 00100010 10011010 00011001 01100011 10011110 00001010 0010-0000
                 8F       44       59       98       C6       79       60       04
              (das Bitdrehen habe ich diesmal gespart)

              Somit ist dann die Vorgabe von PSP nachvollzogen. Hoffentlich habe ich hier auch alles wichtige niedergeschrieben ;-)

              Jörk

              1. Hallo Jörk,

                Jetzt habe ich auch den Rest hinbekommen.

                nur schnell mal Zeichen geben, hab's gesehen
                aber noch nicht nachvollzogen. Sind etliche
                wichtige Erkenntnisse dabei! Danke.

                Und Cheatah hatte doch recht mit dem Kalkrost.

                Klaus

                1. Hallo,

                  auf
                  http://www.boutell.com/gd/
                  hab ich folgendes gefunden:

                  Credits and license terms

                  In order to resolve any possible confusion regarding the authorship of gd, the following copyright statement covers all of the authors who
                  have required such a statement. Although his LZW compression code no longer appears in gd, the authors wish to thank David
                  Rowley for the original LZW-based GIF compression code, which has been removed due to patent concerns. If you are aware of
                  any oversights in this copyright notice, please contact Thomas Boutell who will be pleased to correct them.

                  COPYRIGHT STATEMENT FOLLOWS THIS LINE

                  Portions copyright 1994, 1995, 1996, 1997, 1998, by Cold Spring Harbor Laboratory. Funded under Grant P41-RR02188
                       by the National Institutes of Health.

                  Portions copyright 1996, 1997, 1998, by Boutell.Com, Inc.

                  GIF decompression code copyright 1990, 1991, 1993, by David Koblas (koblas@netcom.com).

                  Non-LZW-based GIF compression code copyright 1998, by Hutchison Avenue Software Corporation
                       (http://www.hasc.com/, info@hasc.com).

                  Permission has been granted to copy and distribute gd in any context, including a commercial application, provided
                       that this notice is present in user-accessible supporting documentation.

                  This does not affect your ownership of the derived work itself, and the intent is to assure proper credit for the authors of gd,
                       not to interfere with your productive use of gd. If you have questions, ask. "Derived works" includes all programs that utilize
                       the library. Credit must be given in user-accessible documentation.

                  Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby
                       granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission
                       notice appear in supporting documentation. This software is provided "as is" without express or implied warranty.

                  END OF COPYRIGHT STATEMENT

                  Ich verstehe das so, daß der LZW-Algorithmus nicht frei ist!
                  Das wird mit dem Verstehen keinen Konflikt geben, aber was
                  ist mit Verwendung?
                  Ist das eine Frage an Boris Hoeller?

                  Klaus

                  1. Hi Klaus,

                    In order to resolve any possible confusion regarding the authorship of gd, the following copyright statement covers all of the authors who
                    have required such a statement. Although his LZW compression code no longer appears in gd, the authors wish to thank David
                    Rowley for the original LZW-based GIF compression code, which has been removed due to patent concerns. If you are aware of
                    any oversights in this copyright notice, please contact Thomas Boutell who will be pleased to correct them.

                    ich verstehe das so, daß der kodierte Algorithmus selber rechtlich geschützt ist, das Verfahren jedoch nicht. Wenn Du also eine eigene Routine schreibst (oder ich *g*), bestehen da eigene Copyrights.

                    Alle Angaben wie immer ohne Winchester ;-)

                    Cheatah

                    1. Hallo,

                      hab' noch angefangen eine Gegenprobe zu machen.
                      Dazu habe ich mein Testbild gespiegelt und als
                      GIF89a gespeichert.

                      --------
                      47 49 46   GIF
                      38 39 61   89a
                      --------   Screen Descriptor
                      10 00      Screen Width
                      02 00      Screen Height
                      B3         Flags
                      00         Background Color Index
                      00
                      --------   Global Color Map
                      00 00 00
                      BF 00 00
                      00 BF 00
                      BF BF 00
                      00 00 BF
                      BF 00 BF
                      00 BF BF
                      C0 C0 C0
                      80 80 80
                      FF 00 00
                      00 FF 00
                      FF FF 00
                      00 00 FF
                      FF 00 FF
                      00 FF FF
                      FF FF FF
                      --------   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
                      F0 B9 C6
                      96 4A E8  
                      98 42 86  
                      08 80 44  
                      59 98 C6  
                      79 60 04
                      00         Block Terminator
                      --------
                      3B         GIF Terminator  
                      --------

                      Es sieht ziemlich ähnlich aus.
                      Die Global Color Map ist identisch.
                      Der Extension Block ist hier nicht vorhanden!
                      Die Daten unterscheiden sich natürlich.

                      Encoded Raster Data Block
                      F0 B9 C6 96 4A E8 98 42 86 08 80 44 59 98 C6 79 60 04

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

                      Die Starttabelle bleibt wie von Jörk aufgestellt.
                      Den praktischen Nährwert der Spiegelung hab'
                      ich jedoch noch nicht recht erfasst. :-(

                      #0 - 00000    
                        #1 - 10000    
                        #2 - 01000    
                        #3 - 11000    
                        #4 - 00100    
                        #5 - 10100    
                        #6 - 01100    
                        #7 - 11100    
                        #8 - 00010    
                        #9 - 10010    
                        #A - 01010    
                        #B - 11010    
                        #C - 00110    
                        #D - 10110    
                        #E - 01110    
                        #F - 11110    
                      <CC> - 00001    
                      <EOI>- 10001

                      Erstmal die erste Hälfte:

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

                      Fünfergruppen:
                      00001 11110 01110 10110 00110 11010 01010 10010 00010 11100 01100 10100 00100 11000 01000 10000 00000

                      Achtergruppen:
                      00001111 10011101 01100011 01101001 01010010 00010111 00011001 01000010 01100001 00010000 00000

                      Gespiegelt und dann in hex:
                      11110000 10111001 11000110 10010110 01001010 11101000 10011000 01000010 10000110 00001000
                      F   0    B   9    C   6    9   6    4   A    E   8    9   8    4   2    8   6    0   8

                      Sollmuster (erste Hälfte laut PSP):
                      F0 B9 C6 96 4A E8 98 42 86 08...

                      Yeah Jörk es klappt!!!
                      Der Rest wird es ja wohl auch noch tun.
                      Aber, es geht ja zu wie beim Krabbenpulen,
                      drücken, drehen und abziehen, und dann nochmal...
                      Wohler wäre mir schon wenn ich das kapieren könnte.

                      Eigentlich sollte es ja auch funktionieren wenn die
                      Starttabelle bzw. String Table richtigrum angelegt
                      wird und dann, wenn es ans Ausgeben des Musters geht,
                      die Bits vom Niederwertigsten an achterweise abgezählt
                      und rausgeschoben werden. Der Rest muß dann aufgehoben
                      werden und ... 2 + 5 = 7 + 1 = 8 ... elende Packerei.

                      Da wird also auch noch Knobelei nötig werden um diese
                      Bitakrobatik einigermaßen sauber hinzukriegen.

                      Außerdem wird es noch eine Rolle spielen wie das ganze
                      dann in die Blöcke gepackt wird.

                      Klaus

                      1. Hi!

                        hab' noch angefangen eine Gegenprobe zu machen.

                        Ist meist auch besser so. Ich hatte z.B. die erste Zeile hinbekommen, und mußte dann meine Erkenntnisse ein wenig revidieren, als ich mich an die zweite machte ...

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

                        Hier hast Du einen Fehler gemacht! Da Du nur 16 Farben verwendest, wird der Farbwert in 4 und nicht in 8 Bit angegeben:

                        Unencoded Raster Data
                        FE DC BA 98 76 54 32 10
                        FE DC BA 98 76 54 32 10

                        Die Starttabelle bleibt wie von Jörk aufgestellt.
                        Den praktischen Nährwert der Spiegelung hab'
                        ich jedoch noch nicht recht erfasst. :-(

                        Das Problem liegt hier in der Art, wie die Code-Fragmente wieder zusammen gesetzt werden sollen. Gehen wir mal von 4 anstelle von 5-stelligen Codes aus:
                        Und die Kodierung würde die Code-Folge 1 2 3 4 5 6 ausgeben. Wenn man jetzt mit der typischen recht-nach-links schreibweise rangeht, aber die einzelnen Codes ja von Links nach rechts aneinanderhängt, kommt ungefähr sowas bei raus:

                        0001 0010 0011 ...
                        12 34 56

                        Das entspricht aber (leider) nicht dem was z.B. PSP ausgeben würde:
                        21 43 65
                        0010 0001 0100 0011     ???

                        Sinn kann man dem ganzen halt erst geben, wenn man die Umwandlung von und nach binär so gestaltet, daß das Bit mit der kleinsten Wertigkeit links steht (unpack "b4", $code):

                        1    2    3    4    5    6
                        1000 0100 1100 0010 1010 0110

                        Für die Umwandlung in ein Byte sollte man jetzt aber 8 Bits auf einmal nutzen, da ja das erste Bit in dieser Reihe das kleinste Bit im Byte sein soll:

                        10000100 11000010 10100110
                           21       43       65     (hier auch wieder das kleinste Bit von links)

                        Erstmal die erste Hälfte:

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

                        siehe oben: <CC> F E D ...

                        Yeah Jörk es klappt!!!
                        Der Rest wird es ja wohl auch noch tun.
                        Aber, es geht ja zu wie beim Krabbenpulen,
                        drücken, drehen und abziehen, und dann nochmal...
                        Wohler wäre mir schon wenn ich das kapieren könnte.

                        Ich hoffe ich konnte noch ein wenig dazu beitragen ...

                        Das Handling gestaltet sich unter Perl gar nicht so kompliziert:

                        $bits = join('', map {unpack 'b8', $_} split('',$uncodiert));

                        ... dann die codierung ;-) ...

                        @bytes = $codierteBits in achterGruppen;

                        $codiert = join('', map {pack 'b8', $_} @bytes);

                        Eigentlich sollte es ja auch funktionieren wenn die
                        Starttabelle bzw. String Table richtigrum angelegt
                        wird und dann, wenn es ans Ausgeben des Musters geht,
                        die Bits vom Niederwertigsten an achterweise abgezählt
                        und rausgeschoben werden. Der Rest muß dann aufgehoben
                        werden und ... 2 + 5 = 7 + 1 = 8 ... elende Packerei.

                        Ich denke, daß man um das andersrum denken nicht herumkommen wird. Zumal die Code-Längen von 2 bis 12 Bit das ganze noch mehr durch den Kakao ziehen würden ...

                        Da wird also auch noch Knobelei nötig werden um diese
                        Bitakrobatik einigermaßen sauber hinzukriegen.

                        s.o.

                        Außerdem wird es noch eine Rolle spielen wie das ganze
                        dann in die Blöcke gepackt wird.

                        Da sehe ich kein Problem:
                        Einfach das kodierte in Blöcke zu 255 trennen, der letzte halt dann wohl meist nicht ganz so viel (z.b. 42). Und dann die Rasterblöcke runterrattern:
                        --------   Raster Data Block
                        04         Code Size
                        FF         Block Byte Count
                        [erster Block]
                        FF         Block Byte Count (neuer Subblock)
                        [zweiter Block]
                        ...
                        2A         Block Byte Count (42)
                        [letzter Block]
                        00         Block Terminator (für den gesamten Raster Data Block)
                        --------

                        Jörk

                        1. Hallo Jörk,

                          Hier hast Du einen Fehler gemacht! ...
                          Unencoded Raster Data
                          FE DC BA 98 76 54 32 10
                          FE DC BA 98 76 54 32 10

                          Ja. Die Nullen hatte ich aber schon weggedacht :-)

                          Das Problem liegt hier in der Art, wie die Code-Fragmente wieder zusammen gesetzt werden sollen.

                          Da muß ich mir leider erstmal PERL reinziehen,
                          kann den Aufwand der Bitfuchserei leider noch nicht einschätzen.

                          $bits = join('', map {unpack 'b8', $_} split('',$uncodiert));
                          ... dann die codierung ;-) ...
                          @bytes = $codierteBits in achterGruppen;
                          $codiert = join('', map {pack 'b8', $_} @bytes);

                          Tja, da muß ich den Kalk wohl noch rieseln lassen.

                          Ich hoffe ich konnte noch ein wenig dazu beitragen ...

                          Es war ja doch der entscheidende Beitrag! Danke.

                          Im Moment knobel ich halt noch an PERL rum.
                          Hab' meine Testdatei mal mit jeder Menge
                          $gif .= hex("xyz's"); zusammengebaut und versucht
                          sie wieder rauszuschreiben.
                          (Bei Cheatah abgeguckt)
                          Der Vorgang funktioniert, auf und schreib und auch wieder zu, die Daten sind aber noch nicht binär.
                          Nur den Dr.Watson muß ich auch noch besänftigen.
                          Werd am Wochenende halt kräftig in SelfHTML schmökern.

                          Klaus

                          1. Hi!

                            Im Moment knobel ich halt noch an PERL rum.
                            Hab' meine Testdatei mal mit jeder Menge
                            $gif .= hex("xyz's"); zusammengebaut und versucht
                            sie wieder rauszuschreiben.

                            Ich habe mal folgendes zusammen getippert ... einfach mal ausprbieren ;-)
                            --------------------------------------------------------------
                            #!/usr/bin/perl

                            sub LZW
                            {
                                my ($inBits, $inStringBytes) = @_;

                            my $outBits, $moreBitsCode, %table, $lastCode, $inStringBits, @inChunks, $outStringBits, $buffer;

                            my $CC = 2 ** $inBits;
                                my $EOI = $CC + 1;

                            $inStringBits = join('', map {unpack 'b8', $_} split('',$inStringBytes));
                                @inChunks = grep {$_} split("(.{0,$inBits})", $inStringBits);

                            @table{(map {unpack("b$inBits", pack("I", $_))} 0..$CC-1), 'CC', 'EOI'} = map {pack("I", $_)} (0..$EOI);
                                $outBits = $inBits + 1;
                                $moreBitsCode = 2 ** $outBits;
                                $lastCode = $EOI;

                            $outStringBits = unpack("b$outBits", $table{'CC'});
                                $buffer = '';

                            foreach $code (@inChunks)
                                {
                                    if (exists $table{$buffer . $code})
                                    {
                                        $buffer .= $code;
                                    }
                                    else
                                    {
                                        $outStringBits .= unpack("b$outBits", $table{$buffer});
                                        $table{$buffer . $code} = pack("I", ++$lastCode);
                                        $buffer = $code;

                            if ($lastCode == $moreBitsCode)
                                        {
                                            ++$outBits;
                                            $moreBitsCode *= 2;
                                        }
                                    }
                                }

                            if ($buffer)
                                {
                                    $outStringBits .= unpack("b$outBits", $table{$buffer});    
                                }

                            $outStringBits .= unpack("b$outBits", $table{'EOI'});

                            return join('', map {pack('b8', $_)} (grep {$_} split('(.{0,8})', $outStringBits)));
                            }

                            my $toCode = pack("h32", "0123456789ABCDEF"x2);
                            my $coded  = &LZW(4, $toCode);

                            print join(' ', map {unpack 'H2', $_} split('',$coded));
                            print "\n10 04 31 48 31 07 25 B5 58 73 8F 44 59 98 C6 79 60 04\n";
                            --------------------------------------------------------------

                            Jörk

                            1. Hallo Jörk,

                              Ich habe mal folgendes zusammen getippert ... einfach mal ausprbieren ;-)

                              Wow, da hab ich ja reichlich was zum Knobeln!
                              Eigentlich wollte ich das Wochenende ja ein wenig
                              geruhsamer angehen lassen.
                              Vielen Dank.

                              Klaus

                              1. Wow,

                                da bin ich mal ein paar Stunden länger weg, und schon geht's wieder rund... :-)

                                Auch ich bedanke mich, und zwar bei allen beteiligten! Jetzt gibt's wieder viel zu lesen *aufdruckerwart* :-)

                                Cheatah

                              2. Hallo Klaus,

                                Ich habe mal folgendes zusammen getippert ... einfach mal ausprbieren ;-)

                                Wow, da hab ich ja reichlich was zum Knobeln!
                                Eigentlich wollte ich das Wochenende ja ein wenig
                                geruhsamer angehen lassen.

                                War wohl nix ;-) Bei dem Script ist noch zu beachten, daß es noch nicht vollständig den Gif-Kompressionalgorithmus wiedergibt. Bei mir wächst zwar immer die Codelänge, wenn die entsprechenden Kriterien erfüllt sind - jedoch können dabei auch mehr als 12Bit entstehen.

                                Gif behandelt aber nur 12stellige Codes. Sollten diese verbraucht sein, so muß man ein (12stelliges) CC ausgeben, die Tabelle wieder auf den Startzustand zurücksetzen, und dann weiter machen. Der Puffer ist dann auch wieder neu einzulesen ...

                                Jörk

                        2. Eigentlich sollte es ja auch funktionieren wenn die
                          Starttabelle bzw. String Table richtigrum angelegt
                          wird und dann, wenn es ans Ausgeben des Musters geht,
                          die Bits vom Niederwertigsten an achterweise abgezählt
                          und rausgeschoben werden. Der Rest muß dann aufgehoben
                          werden und ... 2 + 5 = 7 + 1 = 8 ... elende Packerei.

                          Ich denke, daß man um das andersrum denken nicht herumkommen wird. Zumal die Code-Längen von 2 bis 12 Bit das ganze noch mehr durch den Kakao ziehen würden ...

                          Hi!

                          Ich muss vorausschicken, dass ich nicht so richtig versucht habe, Eure Diskussion nachzuvollziehen; habe es also nur ueberflogen. Mir scheint, dass Ihr ein Problem mit der Notation der Bits habt, was ihre Reihenfolge betrifft. Ich will mal die Standard-Notation erlautern (unabhaengig von jeglicher GIF-Spezifikation):
                          Schreibt man die 8 Bits eines Bytes, dann faengt man mit dem hoechsten Bit links an (Bit 7) und hoert mit dem niedrigsten rechts auf (Bit 0), also
                          7 6 5 4 3 2 1 0.
                          Verarbeitet man jedoch einen (seriellen) Bit-Strom, schreibt man die Bits so, wie sie der Reihe nach kommen. Presst man diesen Bit-Strom in ein Byte-Schema, sind die niedersten Bits die, die im Bit-Strom zuerst kommen. Beispiel: Gegeben sei der Bit-Strom
                          010111110101000
                          Wir wollen diesen in Bytes pressen, wobei wir ein Byte als 5 Bit definieren. Unterteilen wir diesen Bit-Strom also in 5er-Gruppen:
                          01011 11101 01000
                          Da im Bit-Strom die niedersten Bits zuerst kommen, in Byte-Schreibweise aber die hoechsten zuerst, muss man diese Bitgruppen einfach umdrehen. Also:
                          11010 10111 00010
                          Diese Bytes in Hexa:
                          1A  17  02

                          Regel fuer die Praxis: In der Byte-Schreibweise immer von rechts nach links lesen (waehrend der Bit-Strom von links nach rechts gelesen wird).

                          Jetzt kann ich nicht behaupten, dass dies in der GIF-Spezifikation unbdingt genauso gehandled wird, ich halte es aber fuer sehr wahrscheinlich, da es nunmal standardmaessig so gemacht wird.

                          Ich hoffe, ich habe jetzt nicht fuer noch mehr Verwirrung gesorgt.

                          Calocybe

                          1. Hallo Calocybe,

                            Schreibt man die 8 Bits eines Bytes, dann faengt man mit dem hoechsten Bit links an (Bit 7) und hoert mit dem niedrigsten rechts auf (Bit 0), also
                            7 6 5 4 3 2 1 0.
                            Verarbeitet man jedoch einen (seriellen) Bit-Strom, schreibt man die Bits so, wie sie der Reihe nach kommen.

                            ist mir im Prinzip schon klar.
                            Bin es einerseits gewöhnt, daß das LSB den Index null hat,
                            andererseits, daß die Seriallisierung mit dem LSB-first
                            von UARTs oder dgl. besorgt wird.

                            Nun, ich hatte Kompression bislang auch nicht unbedingt
                            als bitorientierte Serialisierung verstanden, wenn ich sie
                            denn überhaupt verstanden hatte.
                            Vorgestellt hatte ich mir darunter eher einen
                            Algorithmus fortlaufender logisch-mathematischer Operationen.

                            Ich hoffe jetzt klüger zu sein.

                            Klaus

        2. Hi,

          Könnt ja sein, daß ich mal Lust bekomme eine LZW Funktion zu schreiben ;-)
          Wäre super, weiß aber auch nicht wie weit Cheatah ist.

          nicht besonders weit. In letzter Zeit streikt der Internet-Zugang hier regelmäßig, und den brauche ich leider zum Testen von Scripts... ein Versuch mit JavaScript scheiterte indes! Und wenn man ständig in den Programmierversuchen zwangsweise unterbrochen wird, kommt man irgendwie aus dem Konzept :-/

          Mir geht es ja mehr ums Verstehen des Verfahrens.

          Mir auch, und das will ich dann noch in Perl umsetzen ;-)

          So, jetzt lese ich den Thread erst mal weiter!

          Cheatah

          1. Hi,

            nicht besonders weit. In letzter Zeit streikt der Internet-Zugang hier regelmäßig, und den brauche ich leider zum Testen von Scripts...

            Warum? Du kannst doch Dein Script auch lokal nutzen (sofern es einige Rahmenbedingungen erfuellt). So hier:

            perl.exe gif.pl > output.gif

            Also den Output des Scripts "gif.pl" in die Datei output.gif umlenken und diese dann irgendwie anschauen. Musst aber gleich mit dem GIF-Header anfangen, also keinen Mime-Typ schreiben. Ich mach das immer so:

            print("Content-type: text/html\n\n")  unless  ($ENV{'SERVER_NAME'} eq "");

            SERVER_NAME ist in einer lokalen Umgebung naemlich gewoehnlich leer bzw. nicht vorhanden.

            »»  ein Versuch mit JavaScript scheiterte indes!

            Na sowas. ;-)

            Calocybe

            1. Hi,

              Warum? Du kannst doch Dein Script auch lokal nutzen (sofern es einige Rahmenbedingungen erfuellt). So hier:

              ich habe auf meinem Rechner praktisch nichts dergleichen installiert und will es momentan auch nicht, weil die Platte (Ersatzplatte, andere ist defekt) so gut wie voll ist... und da ich für meine Onlinezeit nichts bezahle, stört es mich normalerweise auch nicht ;-)

              Cheatah

              1. Hallo Cheatah!

                und da ich für meine Onlinezeit nichts bezahle

                Mann! So gut möchte ich es auch haben! Beteiligst Du Dich dann an meine Telefonrechnung??? <g>

                (354 und ein Paar € für Dezember)

                Bis danndann

                PAF (patrickausfrankfurt)

                1. Hi Patrick,

                  Mann! So gut möchte ich es auch haben! Beteiligst Du Dich dann an meine Telefonrechnung??? <g>

                  klar! Schreibst und bestehst Du ein paar meiner Klausuren? ;-)))

                  Cheatah

  2. http://www.getcruising.com/crypt/_hitmat.html

    dort gibt es ein script, welches folgendes möglich macht:

    <img src="./cgi-bin/hitmat.cgi?index+G=SITE" width=96 height=16
    align=top border=0> Pages Served Since <img src="./hit/since.xbm"
    width=64 height=16 border=0 align=top alt="Last Reset">

    das heisst, dieses script generiert aufgrund der ermittelten zugriffszahl eine grafik, und gibt diese in der html-datei aus.

    Ich denke mal, dass ist etwas woran ihr gerade tüftelt.
    cu