PNG

PNG

Portable Network Graphics — verlustfreie Kompression mit Chunks

PNG (Portable Network Graphics) wurde 1996 als patentfreier Ersatz für GIF entworfen. Eine PNG-Datei beginnt immer mit einer 8 Byte langen Signatur und besteht danach aus einer Folge von „Chunks“.

Jeder Chunk hat denselben Aufbau: 4 Byte Länge, 4 Byte Typ, die Nutzdaten und eine 4 Byte CRC-Prüfsumme. Genau drei Chunk-Typen sind Pflicht: IHDR (Kopf), IDAT (Bilddaten) und IEND (Ende).

Die Bilddaten in IDAT werden mit DEFLATE (zlib) verlustfrei komprimiert — vorher wird jede Bildzeile durch einen „Filter“ vorhergesagt, um die Kompression zu verbessern.

Magic Number: 89 50 4E 47 0D 0A 1A 0A  →  \x89 P N G \r \n \x1a \n

🧩 Aufbau der Datei

So liegen die Bestandteile einer PNG-Datei nacheinander im Speicher.

SignaturKopf/StrukturMetadatenBilddatenEnde
PNG-Signatur
8 Byte
89 50 4E 47 0D 0A 1A 0A
Feste Magic Number. Das \x89 verhindert Verwechslung mit Text, CR/LF erkennt fehlerhafte Zeilenenden-Übertragung.
IHDR-Chunk
25 Byte
00 00 00 0D 49 48 44 52 …
Image Header: Breite, Höhe, Bittiefe, Farbtyp, Kompression, Filter, Interlace.
Optionale Chunks
variabel
PLTE, gAMA, pHYs, tEXt …
Palette, Gamma, physische Auflösung, Textkommentare usw. (Reihenfolge teils festgelegt).
IDAT-Chunk(s)
variabel
49 44 41 54 …(zlib)…
Image Data: zlib/DEFLATE-komprimierte, gefilterte Pixelzeilen. Darf in mehrere Chunks aufgeteilt sein.
IEND-Chunk
12 Byte
00 00 00 00 49 45 4E 44 AE 42 60 82
Image End: leerer Chunk, markiert das Dateiende. CRC ist konstant.

📐 Ablaufdiagramm (ASCII)

Schematischer Gesamtaufbau auf einen Blick.

┌────────────────────────────────────────────────────────────┐
│ 89 50 4E 47 0D 0A 1A 0A   ← 8-Byte Signatur                  │
├────────────────────────────────────────────────────────────┤
│ ┌── Chunk-Schema (für jeden Chunk identisch) ─────────────┐ │
│ │  [Länge 4B] [Typ 4B] [Daten …] [CRC-32 4B]              │ │
│ └─────────────────────────────────────────────────────────┘ │
├────────────────────────────────────────────────────────────┤
│ IHDR  →  Breite/Höhe/Bittiefe/Farbtyp                        │
│ gAMA  →  optional: Gamma                                     │
│ PLTE  →  optional: Farbpalette (bei Farbtyp 3 Pflicht)       │
│ IDAT  →  zlib( filter(zeile_0) + filter(zeile_1) + … )       │
│ IDAT  →  (kann fortgesetzt werden)                           │
│ IEND  →  Ende                                                │
└────────────────────────────────────────────────────────────┘

📊 Tabellen & Referenz

Pflicht- & wichtige Chunks

TypPflichtBedeutung
IHDRJaBildkopf: Abmessungen & Farbcodierung
PLTEBedingtFarbpalette (Pflicht bei Farbtyp 3)
IDATJaKomprimierte Bilddaten
IENDJaDateiende-Markierung
tRNSNeinTransparenz für Paletten/Graustufen
gAMA / sRGBNeinFarb-/Gamma-Verwaltung
tEXt / zTXtNeinTextuelle Metadaten

Farbtypen im IHDR

WertFarbtypKanäle
0Graustufen1 (G)
2Truecolor (RGB)3 (R,G,B)
3Palette (indexiert)1 (Index → PLTE)
4Graustufen + Alpha2 (G,A)
6Truecolor + Alpha4 (R,G,B,A)

⌨️ C-Strukturen & Auslese-Code

Einfache C-Strukturen, die exakt dem Byte-Layout entsprechen, plus Beispielcode zum Einlesen.

PNG-Signatur & Chunk-Kopf · c
#include <stdint.h>

/* Die ersten 8 Bytes jeder PNG-Datei */
static const uint8_t PNG_SIGNATURE[8] = {
    0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A
};

/* Jeder Chunk hat exakt diesen Rahmen (Big-Endian!) */
typedef struct {
    uint32_t length;     /* Länge des data-Feldes in Byte   */
    char     type[4];    /* z. B. "IHDR", "IDAT", "IEND"     */
    /* uint8_t data[length];  -- folgt direkt, variable Länge */
    uint32_t crc;        /* CRC-32 über type[] + data[]      */
} png_chunk_header_t;

ℹ️ Achtung: Alle Mehrbyte-Zahlen in PNG sind Big-Endian (Netzwerk-Byteorder).

IHDR — Bildkopf (13 Byte Nutzdaten) · c
#pragma pack(push, 1)         /* keine Ausrichtungs-Lücken */
typedef struct {
    uint32_t width;            /* Bildbreite  (Big-Endian)     */
    uint32_t height;           /* Bildhöhe    (Big-Endian)     */
    uint8_t  bit_depth;        /* 1,2,4,8 oder 16 Bit/Sample   */
    uint8_t  color_type;       /* 0,2,3,4,6 (siehe Tabelle)    */
    uint8_t  compression;      /* immer 0 = DEFLATE            */
    uint8_t  filter_method;    /* immer 0 = adaptive Filter    */
    uint8_t  interlace;        /* 0 = keins, 1 = Adam7         */
} png_ihdr_t;
#pragma pack(pop)
Signatur prüfen & IHDR auslesen · c
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>  /* ntohl: Big-Endian -> Host */

int read_png_header(FILE *f, png_ihdr_t *out) {
    uint8_t sig[8];
    if (fread(sig, 1, 8, f) != 8) return -1;
    if (memcmp(sig, PNG_SIGNATURE, 8) != 0) return -1; /* keine PNG */

    png_chunk_header_t ch;
    fread(&ch.length, 4, 1, f);
    fread(ch.type,    1, 4, f);
    if (memcmp(ch.type, "IHDR", 4) != 0) return -1;    /* IHDR fehlt */

    fread(out, 1, 13, f);
    out->width  = ntohl(out->width);   /* Byteorder korrigieren */
    out->height = ntohl(out->height);
    printf("PNG %ux%u, %d Bit, Farbtyp %d\n",
           out->width, out->height, out->bit_depth, out->color_type);
    return 0;
}

ℹ️ Big-Endian-Werte müssen auf Little-Endian-Maschinen (x86) getauscht werden.

🗜️ Kompression

PNG nutzt das DEFLATE-Verfahren (LZ77 + Huffman, über die zlib). Vor der Kompression wird jede Bildzeile mit einem von fünf Filtern (None, Sub, Up, Average, Paeth) vorhergesagt. Filter erzeugen kleine Differenzwerte, die sich besonders gut komprimieren lassen — daher ist PNG verlustfrei und trotzdem kompakt.

💡 Wissenswert

✨Die Signatur enthält bewusst \r\n und \n, um beschädigte Text-Übertragungen (CRLF↔LF) zu erkennen.
✨Groß-/Kleinschreibung im Chunk-Typ kodiert Eigenschaften: Bit 5 des 1. Buchstabens = „kritisch vs. optional“.
✨PNG kann keine Animationen — dafür gibt es die Erweiterung APNG mit zusätzlichen fcTL/fdAT-Chunks.
← Zurück zur Übersicht