GIF
GIF (Graphics Interchange Format) wurde 1987 von CompuServe entwickelt. Eine GIF-Datei beginnt mit einem 6 Byte langen Header („GIF87a“ oder „GIF89a“), gefolgt vom Logical Screen Descriptor und einer optionalen globalen Farbtabelle.
GIF ist palettenbasiert: höchstens 256 Farben pro Tabelle. Jedes Bild verweist über einen Index auf diese Palette. Das macht GIF ideal für Grafiken mit wenigen Farben, aber ungeeignet für Fotos.
Die Bilddaten werden mit LZW verlustfrei komprimiert. Mit GIF89a kamen Erweiterungsblöcke hinzu — vor allem die Graphic Control Extension, die Transparenz und Animationen (mehrere Bilder + Verzögerungen) ermöglicht.
47 49 46 38 39 61 → G I F 8 9 a🧩 Aufbau der Datei
So liegen die Bestandteile einer GIF-Datei nacheinander im Speicher.
📐 Ablaufdiagramm (ASCII)
Schematischer Gesamtaufbau auf einen Blick.
┌──────────────────────────────────────────────────────────────┐ │ 'G''I''F''8''9''a' ← Header (6 Byte) │ ├──────────────────────────────────────────────────────────────┤ │ Logical Screen Descriptor (7 Byte) │ │ width(2) height(2) packed(1) bgColor(1) aspect(1) │ │ packed-Bit 7 = globale Tabelle vorhanden │ ├──────────────────────────────────────────────────────────────┤ │ [ Global Color Table ] 2^(N+1) Einträge × RGB │ ├──────────────────────────────────────────────────────────────┤ │ Block-Schleife (bis Trailer): │ │ 21 F9 … Graphic Control Extension (optional, GIF89a) │ │ 2C … Image Descriptor │ │ └─ LZW-Min-Code + [len][daten]…[len][daten] 00 │ │ 21 FF … Application Extension (z. B. NETSCAPE2.0 = Loop) │ ├──────────────────────────────────────────────────────────────┤ │ 3B ← Trailer (Ende) │ └──────────────────────────────────────────────────────────────┘
📊 Tabellen & Referenz
Blocktypen (Introducer-Byte)
| Byte | Block | Bedeutung |
|---|---|---|
| 2C | Image Descriptor | Leitet ein Einzelbild ein |
| 21 F9 | Graphic Control Ext. | Transparenz, Verzögerung, Disposal |
| 21 FE | Comment Extension | Textkommentar |
| 21 01 | Plain Text Ext. | Text als Grafik (selten) |
| 21 FF | Application Ext. | z. B. NETSCAPE2.0 (Loop-Anzahl) |
| 3B | Trailer | Dateiende |
Packed-Feld im Screen Descriptor
| Bit(s) | Feld | Bedeutung |
|---|---|---|
| 7 | Global Color Table Flag | 1 = globale Palette folgt |
| 4–6 | Color Resolution | Bittiefe der Quellfarben − 1 |
| 3 | Sort Flag | Palette nach Häufigkeit sortiert |
| 0–2 | Size of GCT | Tabellengröße = 2^(Wert+1) |
⌨️ C-Strukturen & Auslese-Code
Einfache C-Strukturen, die exakt dem Byte-Layout entsprechen, plus Beispielcode zum Einlesen.
#include <stdint.h>
#pragma pack(push, 1)
typedef struct {
char signature[3]; /* 'G','I','F' */
char version[3]; /* '8','7','a' oder '8','9','a' */
} gif_header_t;
typedef struct {
uint16_t width; /* Leinwandbreite (Little-Endian)*/
uint16_t height; /* Leinwandhöhe (Little-Endian)*/
uint8_t packed; /* siehe Bitfeld unten */
uint8_t bg_color_index;/* Index in globale Palette */
uint8_t pixel_aspect; /* Seitenverhältnis (meist 0) */
} gif_lsd_t;
#pragma pack(pop)
/* Bitmasken für das packed-Feld */
#define GIF_HAS_GCT(p) (((p) & 0x80) != 0)
#define GIF_GCT_SIZE(p) (1 << (((p) & 0x07) + 1)) /* Farbanzahl */ℹ️ Wichtig: GIF speichert Mehrbyte-Zahlen Little-Endian (anders als PNG/JPEG!).
#pragma pack(push, 1)
typedef struct {
uint8_t separator; /* immer 0x2C */
uint16_t left, top; /* Position auf der Leinwand */
uint16_t width, height; /* Bildgröße */
uint8_t packed; /* lokale Palette?, Interlace */
} gif_image_descriptor_t;
typedef struct {
uint8_t introducer; /* 0x21 Extension */
uint8_t label; /* 0xF9 Graphic Control */
uint8_t block_size; /* immer 4 */
uint8_t packed; /* Disposal + Transparenz-Flag */
uint16_t delay_cs; /* Verzögerung in 1/100 Sekunden */
uint8_t transp_index; /* transparenter Paletten-Index */
uint8_t terminator; /* 0x00 */
} gif_gce_t;
#pragma pack(pop)#include <stdio.h>
#include <string.h>
int read_gif_header(FILE *f, gif_lsd_t *lsd) {
gif_header_t h;
if (fread(&h, 1, sizeof h, f) != sizeof h) return -1;
if (memcmp(h.signature, "GIF", 3) != 0) return -1; /* kein GIF */
int v89 = (memcmp(h.version, "89a", 3) == 0);
int v87 = (memcmp(h.version, "87a", 3) == 0);
if (!v89 && !v87) return -1; /* unbekannt */
fread(lsd, 1, sizeof *lsd, f);
printf("GIF%.3s %ux%u Palette: %s (%d Farben)\n",
h.version, lsd->width, lsd->height,
GIF_HAS_GCT(lsd->packed) ? "global" : "keine",
GIF_GCT_SIZE(lsd->packed));
return 0;
}ℹ️ Little-Endian-Felder können auf x86 direkt gelesen werden, auf Big-Endian-CPUs nicht.