Jyrki Alakuijala, Ph.D., Google Inc. 09.03.2023
Zusammenfassung
WebP Lossless ist ein Bildformat für die verlustfreie Komprimierung von ARGB-Bildern. Die das verlustfreie Format die Pixelwerte genau speichert und wiederherstellt, Farbwerte für vollständig transparente Pixel. Universeller Algorithmus für sequenzielle Datenkomprimierung (LZ77), Präfixcodierung und Farb-Cache Komprimierung der Bulk-Daten. Schnellere Decodierung als PNG demonstriert, sowie eine um 25% stärkere Verdichtung, als dies mit im heutigen PNG-Format.
1 Einleitung
In diesem Dokument wird die Darstellung komprimierter Daten einer verlustfreien WebP-Datei beschrieben. Bild. Es dient als detaillierte Referenz für den verlustfreien WebP-Encoder und Decoder-Implementierung verwenden.
In diesem Dokument verwenden wir die Syntax der Programmiersprache C, um zu beschreiben,
und gehen davon aus,
dass eine Funktion zum Lesen von Bits vorhanden ist,
ReadBits(n)
Die Byte werden in der natürlichen Reihenfolge des Streams gelesen, der
und die Bits jedes Byte werden in der am wenigsten signifikanten Bit-Erste-Reihenfolge gelesen. Wann?
werden mehrere Bits gleichzeitig gelesen, wird die Ganzzahl aus dem
Originaldaten in der ursprünglichen Reihenfolge. Die höchstwertigen Bits der zurückgegebenen Daten
Ganzzahl sind auch die höchstwertigen Bits der Originaldaten. Das heißt, die
Anweisung
b = ReadBits(2);
entspricht den beiden folgenden Anweisungen:
b = ReadBits(1);
b |= ReadBits(1) << 1;
Wir gehen davon aus, dass jede Farbkomponente, d. h. Alpha, Rot, Blau und Grün, mit einem 8-Bit-Byte dargestellt wird. Der entsprechende Typ wird als uint8 definiert. A ein ganzes ARGB-Pixel wird durch einen Typ mit dem Namen uint32 dargestellt, der ein vorzeichenloser bestehend aus 32 Bits. Im Code, der das Verhalten der Transformationen, werden diese Werte in den folgenden Bits kodifiziert: Alpha in Bits. 31..24, rot in den Bits 23..16, grün in den Bits 15..8 und blau in den Bits 7..0; Allerdings Implementierungen des Formats können intern eine andere Darstellung verwenden.
Im Grunde enthält ein verlustfreies WebP-Bild Header-Daten, Transformationsinformationen und die eigentlichen Bilddaten. Überschriften enthalten die Breite und Höhe des Bildes. Ein WebP kann ein verlustfreies Bild vier verschiedene Arten von Transformationen durchlaufen, bevor es entropie codiert. Die Transformationsinformationen im Bitstream enthalten die Daten die für die Anwendung der jeweiligen Umkehrtransformationen erforderlich sind.
2 Nomenklatur
- ARGB
- Ein Pixelwert, der aus Alpha-, Rot-, Grün- und Blauwerten besteht.
- ARGB-Bild
- Ein zweidimensionales Array mit ARGB-Pixeln.
- Farbcache
- Ein kleines gehashtes Array zum Speichern kürzlich verwendeter Farben, um mit kürzeren Codes wieder ins Gedächtnis rufen.
- Bild zur Farbindexierung
- Ein eindimensionales Bild mit Farben, das mithilfe einer kleinen Ganzzahl indexiert werden kann (bis zu 256 in WebP, verlustfrei).
- Bild zur Farbtransformation
- Ein zweidimensionales Bild mit Teilauflösung, das Daten über Korrelationen von Farbkomponenten.
- Entfernungskarten
- Ändert die LZ77-Abstände so, dass die kleinsten Werte für Pixel in zweidimensionale Nähe.
- Entropie-Bild
- Ein zweidimensionales Bild mit Teilauflösung, das angibt, welche Entropiecodierung in einem entsprechenden Quadrat im Bild verwendet werden, d. h., jedes Pixel ist ein Meta-Element Präfixcode.
- LZ77
- Ein wörterbuchbasierter Algorithmus für die gleitende Fensterkomprimierung, der entweder oder als Folge früherer Symbole beschrieben.
- Meta-Präfixcode
- Eine kleine Ganzzahl (bis zu 16 Bit), die ein Element im Meta-Präfix indexiert Tabelle.
- Predictor-Bild
- Ein zweidimensionales Bild mit Teilauflösung, das angibt, welcher räumliche Predictor ist für ein bestimmtes Quadrat im Bild verwendet.
- Präfixcode
- Eine klassische Entropiecodierung, bei der eine kleinere Anzahl von Bits verwendet wird für häufigere Codes.
- Präfixcodierung
- Eine Möglichkeit, größere Ganzzahlen zu entropie, um einige Bits der Ganzzahl zu codieren mithilfe eines Entropiecodes und codiert die verbleibenden Bits roh. So können Sie dass die Beschreibungen der Entropiecodes relativ klein bleiben, auch wenn Die Auswahl an Symbolen ist groß.
- Scanzeilenreihenfolge
- Eine Verarbeitungsreihenfolge von Pixeln (von links nach rechts und von oben nach unten), beginnend vom Pixel oben links. Wenn eine Zeile ausgefüllt ist, fahre mit der Spalte der nächsten Zeile.
3 RIFF-Header
Der Anfang des Headers enthält den RIFF-Container. Diese besteht aus den folgende 21 Byte:
- String 'RIFF'.
- Ein Little-Endian-32-Bit-Wert der Chunk-Länge, also der gesamten Größe des Blocks, der vom RIFF-Header gesteuert wird. Normalerweise entspricht dies die Nutzlastgröße (Dateigröße minus 8 Byte: 4 Byte für die RIFF-Funktion) ID und 4 Byte zum Speichern des Werts selbst).
- String "WEBP" (RIFF-Containername).
- String „VP8L“ (FourCC für verlustfreie codierte Bilddaten).
- Ein Little-Endian-Wert von 32 Bit für die Anzahl der Byte im verlustfreiem Stream.
- 1-Byte-Signatur 0x2f.
Die ersten 28 Bits des Bitstreams geben die Breite und Höhe des Bilds an. Breite und Höhe werden wie folgt als 14-Bit-Ganzzahlen decodiert:
int image_width = ReadBits(14) + 1;
int image_height = ReadBits(14) + 1;
Die Genauigkeit von 14 Bit für die Bildbreite und -höhe beschränkt die maximale Größe eines Verlustfreie WebP-Bilder auf 16.384 × 16.384 Pixel.
Das Bit alpha_is_used ist nur ein Hinweis und sollte sich nicht auf die Decodierung auswirken. Er sollte auf 0 gesetzt werden, wenn alle Alphawerte im Bild 255 sind, andernfalls auf 1.
int alpha_is_used = ReadBits(1);
Versionsnummer ist ein 3-Bit-Code, der auf 0 festgelegt werden muss. Jeder andere Wert sollte als Fehler behandelt werden.
int version_number = ReadBits(3);
4 Transformationen
Die Transformationen sind reversible Manipulationen der Bilddaten, durch die die verbleibende symbolische Entropie, indem räumliche und Farbkorrelationen modelliert werden. Sie kann die endgültige Kompression dichter werden.
Ein Bild kann vier Arten von Transformationen durchlaufen. Ein 1-Bit gibt an, vorhandenen Transformationen aus. Jede Transformation darf nur einmal verwendet werden. Die Transformationen werden nur für das ARGB-Bild auf Hauptebene verwendet. der Bilder mit Unterauflösung (Farbtransformationsbild, Entropiebild und Prädiktorbild) haben keine Transformationen. und nicht einmal das 0-Bit für das Ende der Transformationen.
Normalerweise würde ein Encoder diese Transformationen verwenden, um die Shannon-Entropie zu reduzieren. im Restbild. Außerdem können die Transformationsdaten auf Basis der Entropie bestimmt werden. zu minimieren.
while (ReadBits(1)) { // Transform present.
// Decode transform type.
enum TransformType transform_type = ReadBits(2);
// Decode transform data.
...
}
// Decode actual image data (Section 5).
Wenn eine Transformation vorhanden ist, geben die nächsten beiden Bits den Transformationstyp an. Es gibt vier Arten von Transformationen.
enum TransformType {
PREDICTOR_TRANSFORM = 0,
COLOR_TRANSFORM = 1,
SUBTRACT_GREEN_TRANSFORM = 2,
COLOR_INDEXING_TRANSFORM = 3,
};
Auf den Transformationstyp folgen die Transformationsdaten. Transformationsdaten enthalten Informationen, die zur Anwendung der Umkehrtransformation erforderlich sind, und hängt von der Transformationstyp. Die inversen Transformationen werden in umgekehrter Reihenfolge angewendet, werden sie aus dem Bitstream gelesen, d. h. die letzte zuerst.
Als Nächstes beschreiben wir die Transformationsdaten für verschiedene Typen.
4.1 Predictor-Transformation
Die Predictor-Transformation kann zur Reduzierung der Entropie verwendet werden, indem dass benachbarte Pixel oft korrelieren. In der Predictor-Transformation Der aktuelle Pixelwert wird aus den bereits decodierten Pixeln (in Scanlinie) vorhergesagt Reihenfolge) und nur der Restwert (tatsächlich - vorhergesagt) wird codiert. Das grüne -Komponente eines Pixels definiert, welcher der 14 Prädiktoren innerhalb eines bestimmten Block des ARGB-Bildes. Der Vorhersagemodus bestimmt die Art der zu verwenden. Wir teilen das Bild in Quadrate ein und alle Pixel verwenden denselben Vorhersagemodus.
Die ersten 3 Bits an Vorhersagedaten definieren die Blockbreite und -höhe als Zahl. von Bits.
int size_bits = ReadBits(3) + 2;
int block_width = (1 << size_bits);
int block_height = (1 << size_bits);
#define DIV_ROUND_UP(num, den) (((num) + (den) - 1) / (den))
int transform_width = DIV_ROUND_UP(image_width, 1 << size_bits);
Die Transformationsdaten enthalten den Vorhersagemodus für jeden Block des Bildes. Es
ist ein Bild mit Unterauflösung, bei dem die grüne Komponente eines Pixels definiert,
Die 14 Predictors werden für alle block_width * block_height
-Pixel innerhalb
bestimmten Block des ARGB-Bildes. Dieses Bild mit Unterauflösung wird mithilfe von
die in Kapitel 5 beschrieben werden.
Die Anzahl der Blockspalten (transform_width
) wird bei einer zweidimensionalen
Indexierung. Für ein Pixel (x, y) kann der entsprechende Filterblock berechnet werden.
Adresse nach:
int block_index = (y >> size_bits) * transform_width +
(x >> size_bits);
Es gibt 14 verschiedene Vorhersagemodi. In jedem Vorhersagemodus wird der aktuelle Wert Der Pixelwert wird aus einem oder mehreren benachbarten Pixeln vorhergesagt, deren Werte bereits bekannt.
Wir haben die benachbarten Pixel (TL, T, TR und L) des aktuellen Pixels (P) als folgt:
O O O O O O O O O O O
O O O O O O O O O O O
O O O O TL T TR O O O O
O O O O L P X X X X X
X X X X X X X X X X X
X X X X X X X X X X X
Dabei steht TL für oben links, T für oben, TR für oben rechts und L für links. Bei der Zeitpunkt der Vorhersage eines Werts für P sind bereits alle O-, TL-, T-, TR- und L-Pixel bereits verarbeitet wurde und das P-Pixel sowie alle X-Pixel unbekannt sind.
Angesichts der vorhergehenden benachbarten Pixel sind die verschiedenen Vorhersagemodi wie folgt definiert ist.
Modus | Vorhergesagter Wert jedes Kanals des aktuellen Pixels |
---|---|
0 | 0xff000000 (steht für durchgehendes Schwarz im ARGB-Farbraum) |
1 | L |
2 | T |
3 | TR |
4 | TL |
5 | Average2(Average2(L; TR); T) (Durchschnitt2(L; TR); T) |
6 | Average2(L; TL) |
7 | Durchschnitt2(L; T) |
8 | Durchschnitt2(TL; T) |
9 | Average2(T; TR) (Durchschnitt2(T; TR) |
10 | Durchschnitt2(Durchschnitt2(L; TL); Durchschnitt2(T; TR)) |
11 | Select(L; T; TL) |
12 | ClampAddSubtractFull(L, T, TL) |
13 | ClampAddSubtractHalf(Average2(L, T), TL) |
Average2
ist für jede ARGB-Komponente so definiert:
uint8 Average2(uint8 a, uint8 b) {
return (a + b) / 2;
}
Der Auswahl-Predictor ist so definiert:
uint32 Select(uint32 L, uint32 T, uint32 TL) {
// L = left pixel, T = top pixel, TL = top-left pixel.
// ARGB component estimates for prediction.
int pAlpha = ALPHA(L) + ALPHA(T) - ALPHA(TL);
int pRed = RED(L) + RED(T) - RED(TL);
int pGreen = GREEN(L) + GREEN(T) - GREEN(TL);
int pBlue = BLUE(L) + BLUE(T) - BLUE(TL);
// Manhattan distances to estimates for left and top pixels.
int pL = abs(pAlpha - ALPHA(L)) + abs(pRed - RED(L)) +
abs(pGreen - GREEN(L)) + abs(pBlue - BLUE(L));
int pT = abs(pAlpha - ALPHA(T)) + abs(pRed - RED(T)) +
abs(pGreen - GREEN(T)) + abs(pBlue - BLUE(T));
// Return either left or top, the one closer to the prediction.
if (pL < pT) {
return L;
} else {
return T;
}
}
Die Funktionen ClampAddSubtractFull
und ClampAddSubtractHalf
werden ausgeführt
für jede ARGB-Komponente wie folgt:
// Clamp the input value between 0 and 255.
int Clamp(int a) {
return (a < 0) ? 0 : (a > 255) ? 255 : a;
}
int ClampAddSubtractFull(int a, int b, int c) {
return Clamp(a + b - c);
}
int ClampAddSubtractHalf(int a, int b) {
return Clamp(a + (a - b) / 2);
}
Für einige Rahmenpixel gelten spezielle Regeln. Wenn es eine Predictor-Transformation unabhängig vom Modus [0...13] für diese Pixel, den Der vorhergesagte Wert für das Pixel ganz links im Bild ist 0xff000000, alle Die Pixel in der obersten Zeile entsprechen L-Pixel und alle Pixel in der Spalte ganz links T-Pixel.
Die Adressierung des TR-Pixels für Pixel in der Spalte ganz rechts außergewöhnlich. Die Pixel in der Spalte ganz rechts werden mithilfe der Modi vorhergesagt. [0..13], genau wie die Pixel nicht am Rand, sondern das Pixel ganz links auf der Seite. die gleiche Zeile wie das aktuelle Pixel wird als TR-Pixel verwendet.
Der endgültige Pixelwert wird ermittelt, indem jeder Kanal des vorhergesagten Werts addiert wird. in den codierten Restwert ein.
void PredictorTransformOutput(uint32 residual, uint32 pred,
uint8* alpha, uint8* red,
uint8* green, uint8* blue) {
*alpha = ALPHA(residual) + ALPHA(pred);
*red = RED(residual) + RED(pred);
*green = GREEN(residual) + GREEN(pred);
*blue = BLUE(residual) + BLUE(pred);
}
4.2 Farbtransformation
Das Ziel der Farbtransformation besteht darin, die R-, G- und B-Werte jedes einzelnen Pixel. Die Farbtransformation behält den Grünwert (G) unverändert bei, transformiert den den roten (R)-Wert basierend auf dem grünen Wert und wandelt den blauen (B)-Wert basierend auf den grünen und dann auf den roten Wert.
Wie bei der Predictor-Transformation, wird das Bild Der gleiche Transformationsmodus wird für alle Pixel in einem Block verwendet. Für Für jeden Block gibt es drei Typen von Farbtransformationselementen.
typedef struct {
uint8 green_to_red;
uint8 green_to_blue;
uint8 red_to_blue;
} ColorTransformElement;
Die eigentliche Farbtransformation erfolgt durch Definition eines Farbtransformations-Deltas. Die
Das Farbtransformationsdelta hängt vom ColorTransformElement
ab, der gleich
in einem bestimmten Block zu erstellen. Das Delta wird während der
Farbtransformation. Die umgekehrte Farbtransformation addiert dann nur diese Deltas.
Die Funktion zur Farbtransformation ist wie folgt definiert:
void ColorTransform(uint8 red, uint8 blue, uint8 green,
ColorTransformElement *trans,
uint8 *new_red, uint8 *new_blue) {
// Transformed values of red and blue components
int tmp_red = red;
int tmp_blue = blue;
// Applying the transform is just subtracting the transform deltas
tmp_red -= ColorTransformDelta(trans->green_to_red, green);
tmp_blue -= ColorTransformDelta(trans->green_to_blue, green);
tmp_blue -= ColorTransformDelta(trans->red_to_blue, red);
*new_red = tmp_red & 0xff;
*new_blue = tmp_blue & 0xff;
}
ColorTransformDelta
wird mit einer signierten 8-Bit-Ganzzahl berechnet, die ein
3,5-Festkommazahl und ein vorzeichenbehafteter 8-Bit-RGB-Farbkanal (c) [-128..127]
und ist wie folgt definiert:
int8 ColorTransformDelta(int8 t, int8 c) {
return (t * c) >> 5;
}
Eine Konvertierung von der unsignierten 8-Bit-Darstellung (uint8) in die 8-Bit-signierte Darstellung.
one (int8) ist erforderlich, bevor ColorTransformDelta()
aufgerufen wird. Vorzeichenbehafteter Wert
sollte als 8-Bit-Zweierkomplementzahl interpretiert werden (d. h.: Uint8-Bereich)
[128..255] dem Bereich [-128..-1] des konvertierten int8-Werts zugeordnet ist.
Die Multiplikation muss genauer erfolgen (mit mindestens 16-Bit- Genauigkeit). Die Vorzeichenerweiterungseigenschaft der Shift-Operation spielt keine Rolle hier; werden nur die niedrigsten 8 Bits aus dem Ergebnis verwendet, und dort das Vorzeichen Erweiterungsverschiebungen und vorzeichenlose Verschiebungen sind konsistent.
Jetzt beschreiben wir den Inhalt der Farbtransformationsdaten, damit die Decodierung die umgekehrte Farbtransformation durch und stellen die ursprünglichen Rot- und Blauwerte wieder her. Die die ersten 3 Bits der Farbtransformationsdaten enthalten die Breite und Höhe der Bildblock in der Anzahl von Bits, genau wie bei der Predictor-Transformation:
int size_bits = ReadBits(3) + 2;
int block_width = 1 << size_bits;
int block_height = 1 << size_bits;
Der verbleibende Teil der Farbtransformationsdaten enthält ColorTransformElement
für jeden Block des Images. Jedes
ColorTransformElement
'cte'
wird in einem Bild mit Unterauflösung als Pixel behandelt
mit Alphakomponente 255
, rote Komponente cte.red_to_blue
, grün
Komponente ist cte.green_to_blue
und die blaue Komponente ist cte.green_to_red
.
Während der Decodierung werden ColorTransformElement
Instanzen der Blöcke decodiert und
wird die umgekehrte Farbtransformation auf die ARGB-Werte der Pixel angewendet. Als
die bereits erwähnte Umkehrfunktion
ColorTransformElement
-Werten für die roten und blauen Kanäle fest. Der Alpha- und der grüne
bleiben die Kanäle unverändert.
void InverseTransform(uint8 red, uint8 green, uint8 blue,
ColorTransformElement *trans,
uint8 *new_red, uint8 *new_blue) {
// Transformed values of red and blue components
int tmp_red = red;
int tmp_blue = blue;
// Applying the inverse transform is just adding the
// color transform deltas
tmp_red += ColorTransformDelta(trans->green_to_red, green);
tmp_blue += ColorTransformDelta(trans->green_to_blue, green);
tmp_blue +=
ColorTransformDelta(trans->red_to_blue, tmp_red & 0xff);
*new_red = tmp_red & 0xff;
*new_blue = tmp_blue & 0xff;
}
4.3 Green-Transformation subtrahieren
Die Transformation „Grüne Subtraktion“ subtrahiert grüne Werte von den Rot- und Blauwerten für jedes Pixel. Wenn diese Transformation vorhanden ist, muss der Decoder das grüne den roten und den blauen Wert. Dem sind keine Daten zugeordnet Transformieren. Der Decoder wendet die Inverse-Transformation wie folgt an:
void AddGreenToBlueAndRed(uint8 green, uint8 *red, uint8 *blue) {
*red = (*red + green) & 0xff;
*blue = (*blue + green) & 0xff;
}
Diese Transformation ist redundant, da sie mit der Farbtransformation modelliert werden kann, aber Da es hier keine zusätzlichen Daten gibt, kann die Subtraktion-Grün-Transformation codiert mit weniger Bits als eine vollständige Farbtransformation.
4.4 Transformation der Farbindexierung
Wenn nicht viele eindeutige Pixelwerte vorhanden sind, ist es möglicherweise effizienter, eine color Index-Array und ersetzen die Pixelwerte durch die Indexe des Arrays. Farbe mit der Indexierungs-Transformation. Im Kontext von WebP Lossless nennen Sie dies keine Palettentransformation, da eine ähnliche, gibt es das dynamische Konzept bei der verlustfreien WebP-Codierung: Farbcache.)
Die Farbindexierungstransformation überprüft die Anzahl der eindeutigen ARGB-Werte im Bild. Wenn diese Zahl unter einem Schwellenwert (256) liegt, wird ein Array dieser ARGB-Werte, die dann verwendet werden, um die Pixelwerte durch die entsprechender Index: Der grüne Kanal der Pixel wird durch den sind alle Alphawerte auf 255 und alle Rot- und Blauwerte auf 0 gesetzt.
Die Transformationsdaten enthalten die Farbtabellengröße und die Einträge in der Farbe . Der Decoder liest die Transformationsdaten zur Farbindexierung so aus:
// 8-bit value for the color table size
int color_table_size = ReadBits(8) + 1;
Die Farbtabelle wird im Bildspeicherformat selbst gespeichert. Farbtabelle
erhalten Sie, indem Sie ein Bild ohne RIFF-Header, Bildgröße und
wird unter der Annahme der Höhe von 1 Pixel und der Breite von color_table_size
transformiert.
Die Farbtabelle ist immer subtraktiv codiert, um die Bildentropie zu reduzieren. Die Deltas
der Farbpaletten enthalten normalerweise viel weniger Entropie als die Farben
was zu erheblichen Einsparungen bei kleineren Bildern führt. Beim Decodieren
können Sie jede endgültige Farbe in der Farbtabelle abrufen, indem Sie die vorherige Farbe
von jeder ARGB-Komponente separat anpassen und die am wenigsten
signifikanten 8 Bit aus.
Bei der Umkehrtransformation für das Bild werden einfach die Pixelwerte (die (Indexe zur Farbtabelle) mit den tatsächlichen Werten der Farbtabelle. Die Indexierung basierend auf der Grünkomponente der ARGB-Farbe.
// Inverse transform
argb = color_table[GREEN(argb)];
Ist der Index gleich oder größer als color_table_size
, wird der "argb"-Farbwert verwendet.
sollte auf 0x00000000 (transparentes Schwarz) festgelegt sein.
Wenn die Farbtabelle klein ist (mindestens 16 Farben), mehrere Pixel die zu einem einzigen Pixel gebündelt sind. Die Pixel-Bündelung umfasst mehrere (2, 4 oder 8) Pixel in ein einzelnes Pixel umwandeln und dabei die Bildbreite reduzieren. Google Pixel ermöglicht Bündelung eine effizientere Enropiecodierung der gemeinsamen Verteilung von benachbarten Pixeln. Dies bringt einige Vorteile mit der arithmetischen Codierung Entropie-Code, kann aber nur verwendet werden, wenn 16 oder weniger eindeutige Werte vorhanden sind.
color_table_size
gibt an, wie viele Pixel kombiniert werden:
int width_bits;
if (color_table_size <= 2) {
width_bits = 3;
} else if (color_table_size <= 4) {
width_bits = 2;
} else if (color_table_size <= 16) {
width_bits = 1;
} else {
width_bits = 0;
}
width_bits
hat den Wert 0, 1, 2 oder 3. Der Wert 0 bedeutet, dass kein Pixel vorhanden ist.
wird für das Bild gebündelt. Der Wert 1 gibt an, dass zwei Pixel
kombiniert und jedes Pixel hat einen Bereich von [0 bis 15]. Ein Wert von 2 bedeutet, dass
vier Pixel kombiniert, und jedes Pixel hat einen Bereich von [0..3]. Ein Wert von 3
gibt an, dass acht Pixel kombiniert werden und jedes Pixel einen Bereich von [0..1] hat,
also ein Binärwert.
Die Werte werden wie folgt in die grüne Komponente gepackt:
width_bits
= 1: Für jeden x-Wert, wobei x Displayanzeige 0 (Mod. 2) ein grünes Symbol darstellt der Wert bei x in den 4 niedrigstwertigen Bits des der grüne Wert bei x / 2 und ein grüner Wert bei x + 1 4 höchstwertige Bits des grünen Werts bei x / 2.width_bits
= 2: Für jeden x-Wert, wobei x anzupassen 0 (Mod. 4) ein grünes Symbol ist der Wert bei x in den beiden Bits mit der geringsten Signifikanz des grüner Wert bei x / 4 und grüne Werte bei x + 1 bis x + 3 sind in zu den höherwertigen Bits des grünen Werts bei x / 4.width_bits
= 3: Für jeden x-Wert, wobei x anzupassen 0 (Mod. 8) ein grünes Symbol ist Der Wert bei x befindet sich im niedrigstwertigen Bit des grünen Balkens der Wert bei x / 8 und die grünen Werte bei x + 1 bis x + 7 sind in der richtigen Reihenfolge angeordnet. zu den höherwertigen Bits des grünen Werts bei x / 8.
Nach dem Lesen dieser Transformation wird image_width
von width_bits
in einer Substichprobe erfasst. Dieses
beeinflusst die Größe nachfolgender Transformationen. Die neue Größe kann mit
DIV_ROUND_UP
wie zuvor definiert.
image_width = DIV_ROUND_UP(image_width, 1 << width_bits);
5 Bilddaten
Bilddaten sind ein Array von Pixelwerten in Scanlinienreihenfolge.
5.1 Rollen von Bilddaten
Wir verwenden Bilddaten in fünf verschiedenen Rollen:
- ARGB-Bild: Speichert die tatsächlichen Pixel des Bilds.
- Entropie-Image: Speichert die Meta-Präfixcodes (siehe „Decodierung von Meta-Präfixcodes“.
- Predictor-Bild: Speichert die Metadaten für die Predictor-Transformation (siehe "Predictor Transform").
- Bild zur Farbtransformation: erstellt aus
ColorTransformElement
-Werten (definiert in "Color Transform") für verschiedene Blöcke des Bildes. - Bild zur Farbindexierung: ein Array der Größe
color_table_size
(bis zu 256 ARGB) -Werte), speichern die Metadaten für die Farbindexierungstransformation (siehe „Color Indexing Transform“) verwenden.
5.2 Codierung von Bilddaten
Die Codierung von Bilddaten ist unabhängig von ihrer Rolle.
Das Bild wird zunächst in eine Reihe von Blöcken mit fester Größe unterteilt, die normalerweise 16 x 16 Pixel groß sind. Blöcke). Jeder dieser Blöcke wird mit eigenen Entropiecodes modelliert. Außerdem mehrere Blöcke können dieselben Entropiecodes verwenden.
Grund: Das Speichern eines Entropiecodes ist kostenpflichtig. Diese Kosten können minimiert werden, wenn statistisch ähnliche Blöcke einen Entropiecode teilen, wodurch dieser Code nur einmal. Ein Encoder kann beispielsweise ähnliche Blöcke finden, indem er sie gruppiert. durch wiederholtes Verbinden eines Paars zufälliger Werte ausgewählte Cluster, wenn dadurch die Gesamtmenge der für die Codierung erforderlichen Bits reduziert wird. auf das Bild.
Jedes Pixel wird mithilfe einer der drei möglichen Methoden codiert:
- Präfixcodierte Literale: Jeder Kanal (grün, rot, blau und Alpha) ist entropie codiert.
- LZ77-Rückwärtsreferenz: Eine Folge von Pixeln wird von einer anderen Stelle im auf das Bild.
- Farb-Cache-Code: Verwendung eines kurzen multiplikativen Hash-Codes (Farb-Cache) Index) einer kürzlich erkannten Farbe.
In den folgenden Unterabschnitten wird jede dieser Anforderungen ausführlich beschrieben.
5.2.1 Präfix-codierte Literale
Das Pixel wird als präfixcodierte Werte von Grün, Rot, Blau und Alpha (in dieser Reihenfolge). In Abschnitt 6.2.3 finden Sie Informationen zur Details.
5.2.2 LZ77-Rückwärtsreferenz
Rückwärtsverweise sind Tupel aus length und distance code:
- Die Länge gibt an, wie viele Pixel in der Reihenfolge der Scanzeilen kopiert werden sollen.
- Der Entfernungscode ist eine Zahl, die die Position eines zuvor gesehenen Pixel, von dem die Pixel kopiert werden sollen. Die genaue Zuordnung ist wie unten beschrieben.
Die Längen- und Entfernungswerte werden mithilfe der LZ77-Präfixcodierung gespeichert.
Bei der LZ77-Präfixcodierung werden große Ganzzahlwerte in zwei Teile unterteilt: das Präfix Code und die zusätzlichen Bits. Der Präfixcode wird als Entropiecode gespeichert, während die zusätzlichen Bits unverändert (ohne Entropiecode) gespeichert werden.
Grund: Dieser Ansatz reduziert den Speicherbedarf für die Entropie. Code. Außerdem sind große Werte meist selten, sodass zusätzliche Bits für sehr nur wenige Werte im Bild. Dieser Ansatz führt also zu einer besseren Komprimierung insgesamt.
In der folgenden Tabelle sind die Präfixcodes und zusätzlichen Bits aufgeführt, die zum Speichern verwendet werden. unterschiedliche Wertebereiche.
Wertebereich | Präfixcode | Zusätzliche Bits |
---|---|---|
1 | 0 | 0 |
2 | 1 | 0 |
3 | 2 | 0 |
4 | 3 | 0 |
5..6 | 4 | 1 |
7..8 | 5 | 1 |
9.12 | 6 | 2 |
13..16 | 7 | 2 |
… | … | … |
+3072–4096 | 23 | 10 |
… | … | … |
524289..786432 | 38 | 18 |
786433..1048576 | 39 | 18 |
Der Pseudocode zum Abrufen eines Werts (Länge oder Entfernung) aus dem Präfixcode lautet wie folgt: folgt:
if (prefix_code < 4) {
return prefix_code + 1;
}
int extra_bits = (prefix_code - 2) >> 1;
int offset = (2 + (prefix_code & 1)) << extra_bits;
return offset + ReadBits(extra_bits) + 1;
Entfernungszuordnung
Wie bereits erwähnt, ist ein Entfernungscode eine Zahl, die die Position eines zuvor gesehenen Pixel, von dem die Pixel kopiert werden sollen. Dieser Unterabschnitt definiert die Zuordnung zwischen einem Entfernungscode und der Position eines vorherigen Pixel.
Entfernungscodes, die größer als 120 sind, geben die Pixelentfernung in Scanlinienreihenfolge an. um 120 verrechnet.
Die kleinsten Entfernungscodes [1..120] sind speziell und für einen Schließvorgang reserviert. Stadtteil des aktuellen Pixels. Dieser Stadtteil hat 120 Pixel:
- Pixel, die sich 1 bis 7 Zeilen über dem aktuellen Pixel befinden und bis zu 8 Spalten umfassen
bis zu 7 Spalten rechts neben dem aktuellen Pixel. [Gesamt
wie Pixel =
7 * (8 + 1 + 7) = 112
]. - Pixel, die sich in derselben Zeile wie das aktuelle Pixel befinden und bis zu 8 Pixel groß sind
Spalten links neben dem aktuellen Pixel. [
8
solche Pixel].
Zuordnung zwischen dem Entfernungscode distance_code
und dem Nachbarpixel
Der Offset (xi, yi)
lautet wie folgt:
(0, 1), (1, 0), (1, 1), (-1, 1), (0, 2), (2, 0), (1, 2),
(-1, 2), (2, 1), (-2, 1), (2, 2), (-2, 2), (0, 3), (3, 0),
(1, 3), (-1, 3), (3, 1), (-3, 1), (2, 3), (-2, 3), (3, 2),
(-3, 2), (0, 4), (4, 0), (1, 4), (-1, 4), (4, 1), (-4, 1),
(3, 3), (-3, 3), (2, 4), (-2, 4), (4, 2), (-4, 2), (0, 5),
(3, 4), (-3, 4), (4, 3), (-4, 3), (5, 0), (1, 5), (-1, 5),
(5, 1), (-5, 1), (2, 5), (-2, 5), (5, 2), (-5, 2), (4, 4),
(-4, 4), (3, 5), (-3, 5), (5, 3), (-5, 3), (0, 6), (6, 0),
(1, 6), (-1, 6), (6, 1), (-6, 1), (2, 6), (-2, 6), (6, 2),
(-6, 2), (4, 5), (-4, 5), (5, 4), (-5, 4), (3, 6), (-3, 6),
(6, 3), (-6, 3), (0, 7), (7, 0), (1, 7), (-1, 7), (5, 5),
(-5, 5), (7, 1), (-7, 1), (4, 6), (-4, 6), (6, 4), (-6, 4),
(2, 7), (-2, 7), (7, 2), (-7, 2), (3, 7), (-3, 7), (7, 3),
(-7, 3), (5, 6), (-5, 6), (6, 5), (-6, 5), (8, 0), (4, 7),
(-4, 7), (7, 4), (-7, 4), (8, 1), (8, 2), (6, 6), (-6, 6),
(8, 3), (5, 7), (-5, 7), (7, 5), (-7, 5), (8, 4), (6, 7),
(-6, 7), (7, 6), (-7, 6), (8, 5), (7, 7), (-7, 7), (8, 6),
(8, 7)
Beispielsweise gibt der Entfernungscode 1
einen Offset von (0, 1)
für den
benachbarten Pixel, d. h. das Pixel über dem aktuellen Pixel (0 Pixel
und 1 Pixel Differenz in Y-Richtung.
In ähnlicher Weise gibt der Abstandscode 3
das Pixel oben links an.
Der Decoder kann den Entfernungscode distance_code
in eine Scanzeilenreihenfolge umwandeln
Abstand dist
so:
(xi, yi) = distance_map[distance_code - 1]
dist = xi + yi * image_width
if (dist < 1) {
dist = 1
}
Dabei ist distance_map
die oben angegebene Zuordnung und image_width
die Breite
des Bilds in Pixeln.
5.2.3 Farbcache-Codierung
Im Farb-Cache wird eine Reihe von Farben gespeichert, die kürzlich im Bild verwendet wurden.
Grund: Auf diese Weise kann auf die zuletzt verwendeten Farben verwiesen werden. als sie mit den beiden anderen Methoden (siehe 5.2.1 und 5.2.2).
Farbcache-Codes werden wie folgt gespeichert. Erstens gibt es einen 1-Bit-Wert, gibt an, ob der Farb-Cache verwendet wird. Wenn dieses Bit 0 ist, gibt es keine Farb-Cache-Codes existieren, und sie werden nicht in dem Präfixcode übertragen, der den grünen und die Präfixcodes für die Länge. Wenn dieses Bit jedoch 1 ist, hat der Farbcache Größe wird als Nächstes gelesen:
int color_cache_code_bits = ReadBits(4);
int color_cache_size = 1 << color_cache_code_bits;
color_cache_code_bits
definiert die Größe des Farbcache (1 <<
color_cache_code_bits
). Der Bereich der zulässigen Werte für
color_cache_code_bits
ist [1..11]. Konforme Decoder müssen auf eine
Bitstreams für andere Werte.
Ein Farbcache ist ein Array der Größe color_cache_size
. In jedem Eintrag wird ein ARGB-Wert
Farbe. Farben werden anhand von (0x1e35a7bd * color) >> (32 -
color_cache_code_bits)
indexiert. In einem Farbcache wird nur eine Suche durchgeführt. es gibt keine
Konfliktlösung.
Zu Beginn der Decodierung oder Codierung eines Bildes werden alle Einträge in allen Farben werden auf null gesetzt. Der Farb-Cache-Code wird in diese Farbe konvertiert, Decodierungszeit. Der Status des Farb-Cache wird durch Einfügen aller der durch Rückwärtsverweise oder als Literale erzeugt wird, in den Cache in der sie im Stream erscheinen.
6 Entropiecode
6.1 Übersicht
Die meisten Daten werden mit einem kanonischen Präfixcode codiert. Daher werden die Codes übertragen, indem die Präfixcodelängen wie folgt gesendet werden: im Gegensatz zu den tatsächlichen Präfixcodes.
Insbesondere wird beim Format eine räumliche Variantenpräfixcodierung verwendet. In anderen unterschiedliche Blöcke des Bildes können unterschiedliche Entropie enthalten Codes.
Grund: Verschiedene Bereiche des Bildes können unterschiedliche Eigenschaften haben. Die Möglichkeit, verschiedene Entropiecodes zu verwenden, bietet mehr Flexibilität und eine potenziell bessere Komprimierung.
6.2 Details
Die codierten Bilddaten bestehen aus mehreren Teilen:
- Präfixcodes decodieren und erstellen
- Meta-Präfixcodes.
- Entropiecodierte Bilddaten.
Für jedes Pixel (x, y) gibt es eine Reihe von fünf Präfixcodes, die . Diese Codes sind in Bitstream-Reihenfolge:
- Präfixcode 1: wird für den grünen Kanal, die Rückwärtsreferenz und Farbcache verwenden.
- Präfixcode 2, 3 und 4: Wird für Rot-, Blau- und Alpha-Kanäle verwendet. .
- Präfix #5: Wird für die Rückwärtsreferenz auf Entfernung verwendet.
Ab hier wird diese Gruppe als Präfixcodegruppe bezeichnet.
6.2.1 Präfixcodes decodieren und erstellen
In diesem Abschnitt wird beschrieben, wie die Präfixcodelängen aus dem Bitstream gelesen werden.
Die Länge des Präfixcodes kann auf zwei Arten codiert werden. Die verwendete Methode ist angegeben durch einen 1-Bit-Wert.
- Wenn dieses Bit 1 ist, ist es ein Code mit einfacher Codelänge.
- Wenn dieses Bit 0 ist, ist es ein Code mit normaler Codelänge.
In beiden Fällen kann es nicht verwendete Codelängen geben, die immer noch Teil des . Dies ist möglicherweise ineffizient, ist jedoch durch das Format zulässig. Die beschriebene Baumstruktur muss eine vollständige Binärstruktur sein. Ein einzelner Blattknoten als vollständigen Binärbaum betrachtet und kann entweder mit dem einfachen Codelängencode oder normalen Codelängencode angeben. Beim Codieren eines einzelnen Blattes mit dem Code für die normale Codelänge, wobei alle Codelängen bis auf eine Nullen sind. und der Wert für einen einzelnen Blattknoten mit der Länge 1 gekennzeichnet ist, auch wenn keine Bits werden verbraucht, wenn dieser einzelne Blattknotenbaum verwendet wird.
Code für einfache Codelänge
Diese Variante wird im Sonderfall verwendet, wenn nur ein oder zwei Präfixsymbole vorhanden sind.
den Bereich [0..255] mit der Codelänge 1
. Alle anderen Präfixcode-Längen sind
implizit Nullen entspricht.
Das erste Bit gibt die Anzahl der Symbole an:
int num_symbols = ReadBits(1) + 1;
Im Folgenden sind die Symbolwerte aufgeführt.
Dieses erste Symbol wird mit 1 oder 8 Bit codiert, je nach
is_first_8bits
Der Bereich ist [0..1] bzw. [0..255]. Die zweite
-Zeichen, falls vorhanden, wird immer davon ausgegangen, dass sie sich im Bereich [0...255] befindet und codiert ist.
mit 8 Bit.
int is_first_8bits = ReadBits(1);
symbol0 = ReadBits(1 + 7 * is_first_8bits);
code_lengths[symbol0] = 1;
if (num_symbols == 2) {
symbol1 = ReadBits(8);
code_lengths[symbol1] = 1;
}
Die beiden Symbole sollten sich unterscheiden. Doppelte Symbole sind zwar zulässig, ineffizient ist.
Hinweis:Ein weiterer Sonderfall ist, wenn alle Präfixcodelängen Nullen sind (ein
leerer Präfixcode). Beispielsweise kann ein Präfixcode für Entfernung leer sein, wenn
gibt es keine Rückwärtsbezüge. Präfixcodes für Alpha-, Rot- und
Blau kann leer sein, wenn alle Pixel innerhalb desselben Metapräfixcodes erzeugt werden.
mithilfe des Farb-Cache. Dieser Fall muss jedoch nicht gesondert behandelt werden,
Leere Präfixcodes können so codiert werden, dass sie ein einzelnes Symbol 0
enthalten.
Code mit normaler Codelänge
Die Codelängen des Präfixcodes passen in 8 Bit und werden wie folgt gelesen.
Zuerst gibt num_code_lengths
die Anzahl der Codelängen an.
int num_code_lengths = 4 + ReadBits(4);
Die Codelängen werden selbst mit Präfixcodes codiert. niedrigerer Code
Längen, code_length_code_lengths
, müssen zuerst gelesen werden. Die übrigen Elemente
code_length_code_lengths
(gemäß Bestellung in kCodeLengthCodeOrder
)
Nullen sind.
int kCodeLengthCodes = 19;
int kCodeLengthCodeOrder[kCodeLengthCodes] = {
17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
};
int code_length_code_lengths[kCodeLengthCodes] = { 0 }; // All zeros
for (i = 0; i < num_code_lengths; ++i) {
code_length_code_lengths[kCodeLengthCodeOrder[i]] = ReadBits(3);
}
Als Nächstes wird bei ReadBits(1) == 0
die maximale Anzahl verschiedener gelesener Symbole
(max_symbol
) wird für jeden Symboltyp (A, R, G, B und Entfernung) auf den
Alphabetgröße:
- G-Kanal: 256 + 24 +
color_cache_size
- Andere Literale (A, R und B): 256
- Entfernungscode: 40
Andernfalls werden sie so definiert:
int length_nbits = 2 + 2 * ReadBits(3);
int max_symbol = 2 + ReadBits(length_nbits);
Wenn max_symbol
größer als das Alphabet für den Symboltyp ist, gibt der Wert
Bitstream ist ungültig.
Aus code_length_code_lengths
wird dann eine Präfixtabelle erstellt, die zum Lesen
bis max_symbol
Codelängen.
- Code [0..15] gibt Literalcodelängen an.
- Der Wert 0 bedeutet, dass keine Symbole codiert wurden.
- Die Werte [1..15] geben die Bitlänge des jeweiligen Codes an.
- Code 16 wiederholt den vorherigen Wert ungleich null [3 bis 6] Mal, d. h.,
3 + ReadBits(2)
Mal. Wenn Code 16 vor einem Wert ungleich null steht ausgegeben wurde, wird der Wert 8 wiederholt. - Code 17 sendet eine Reihe von Nullen der Länge [3...10], also
3 + ReadBits(3)
-mal. - Code 18 sendet eine Reihe von Nullen der Länge [11..138], das heißt,
11 + ReadBits(7)
Mal.
Sobald Codelängen gelesen wurden, wird ein Präfixcode für jeden Symboltyp (A, R, G, B und Abstand) wird durch die entsprechende Schriftgröße gebildet.
Der Code für die normale Codelänge muss einen vollständigen Entscheidungsbaum codieren, d. h. die Summe
2 ^ (-length)
für alle Codes ungleich null muss genau eins sein. Es gibt jedoch
Eine Ausnahme von dieser Regel ist der Baum mit einem einzelnen Blattknoten, bei dem der Blattknoten
Der Wert ist mit dem Wert 1 gekennzeichnet, die anderen Werte sind Nullen.
6.2.2 Meta-Präfixcodes decodieren
Wie bereits erwähnt, ermöglicht das Format die Verwendung verschiedener Präfixcodes für unterschiedliche Bildblöcke zu erstellen. Meta-Präfixcodes sind Indexe, die angeben, Präfixcodes, die in verschiedenen Teilen des Images verwendet werden.
Meta-Präfixcodes dürfen nur verwendet werden, wenn das Bild im role eines ARGB-Bilds.
Es gibt zwei Möglichkeiten für die Meta-Präfixcodes. Diese werden durch 1-Bit Wert:
- Wenn dieses Bit null ist, wird nur ein einziger Meta-Präfixcode überall in auf das Bild. Es werden keine weiteren Daten gespeichert.
- Wenn dieses Bit eins ist, verwendet das Image mehrere Meta-Präfixcodes. Diese Meta-Tags Präfixcodes werden als Entropie-Image gespeichert, wie unten beschrieben.
Die roten und grünen Komponenten eines Pixels definieren einen 16-Bit-Meta-Präfixcode, der in bestimmten Block des ARGB-Bildes.
Entropiebild
Das Entropie-Image definiert, welche Präfixcodes in verschiedenen Teilen des Bild.
Die ersten 3 Bits enthalten den Wert prefix_bits
. Die Abmessungen der Entropie
Bilder von prefix_bits
abgeleitet:
int prefix_bits = ReadBits(3) + 2;
int prefix_image_width =
DIV_ROUND_UP(image_width, 1 << prefix_bits);
int prefix_image_height =
DIV_ROUND_UP(image_height, 1 << prefix_bits);
Dabei wurde DIV_ROUND_UP
wie zuvor definiert.
Die nächsten Bits enthalten ein Entropiebild mit der Breite prefix_image_width
und der Höhe
prefix_image_height
.
Interpretation von Meta-Präfixcodes
Die Anzahl der Präfixcodegruppen im ARGB-Bild lässt sich ermitteln, indem Sie den größten Metapräfixcode aus dem Entropiebild:
int num_prefix_groups = max(entropy image) + 1;
Dabei gibt max(entropy image)
den größten im
Entropiebild.
Da jede Präfixcodegruppe fünf Präfixcodes enthält, ist die Gesamtzahl der Präfixcodes Codes lautet:
int num_prefix_codes = 5 * num_prefix_groups;
Mit einem Pixel (x, y) im ARGB-Bild erhalten wir das entsprechende Präfix die wie folgt verwendet werden:
int position =
(y >> prefix_bits) * prefix_image_width + (x >> prefix_bits);
int meta_prefix_code = (entropy_image[position] >> 8) & 0xffff;
PrefixCodeGroup prefix_group = prefix_code_groups[meta_prefix_code];
bei denen wir von einer PrefixCodeGroup
-Struktur ausgegangen sind,
steht für einen Satz von fünf Präfixcodes. Außerdem ist prefix_code_groups
ein Array von
PrefixCodeGroup
(mit der Größe num_prefix_groups
).
Der Decoder verwendet dann die Präfixcodegruppe prefix_group
, um das Pixel zu decodieren
(x, y), wie unter "Entropie-codiertes Bild decodieren" erläutert.
Daten“ hinzu.
6.2.3 Entropie-codierte Bilddaten decodieren
Für die aktuelle Position (x, y) im Bild identifiziert der Decoder zuerst den zugehörigen Präfixcodegruppe (wie im letzten Abschnitt erläutert). In Anbetracht der Präfixcodegruppe wird das Pixel wie folgt gelesen und decodiert.
Lesen Sie als Nächstes das Symbol S aus dem Bitstream mit dem Präfixcode #1 aus. Beachten Sie, dass S
eine beliebige Ganzzahl im Bereich von 0
bis
(256 + 24 +
color_cache_size
- 1)
.
Die Interpretation von „S“ hängt von seinem Wert ab:
- Wenn S < 256
- Verwenden Sie S für die grüne Komponente.
- Lesen Sie Rot mit Präfixcode #2 aus dem Bitstream.
- Lesen Sie Blau aus dem Bitstream mit dem Präfixcode #3.
- Liest Alpha aus dem Bitstream mit dem Präfixcode #4.
- Wenn S >= 256 & S < 256 + 24
- Verwenden Sie als Längenpräfixcode S-256.
- Liest zusätzliche Bits für die Länge aus dem Bitstream.
- Die Rückwärtsreferenzlänge L aus dem Längenpräfixcode und dem die zusätzlichen Bits vorgelesen werden.
- Lesen Sie den Entfernungspräfix-Code aus dem Bitstream mit dem Präfixcode #5.
- Liest zusätzliche Bits für die Entfernung vom Bitstream.
- Rückbezugsentfernung D aus dem Entfernungspräfixcode bestimmen und die zusätzlichen Teile gelesen.
- L-Pixel (in Scanzeilenreihenfolge) aus der Pixelsequenz kopieren, die an der aktuellen Position minus D Pixel.
- Wenn S >= 256 + 24
- Verwende S - (256 + 24) als Index für den Farb-Cache.
- Ruft die ARGB-Farbe aus dem Farbcache bei diesem Index ab.
7 Gesamtstruktur des Formats
Unten sehen Sie eine Darstellung des Formats als angereicherte Backus-Naur-Form (Augmented Backus-Naur Form, ABNF). RFC 5234 RFC 7405. Sie deckt nicht alle Details ab. End-of-Image (EOI) wird nur implizit in die Anzahl der Pixel codiert (image_width * image_height).
Beachten Sie, dass *element
bedeutet, dass element
0-mal oder öfter wiederholt werden kann. 5element
bedeutet, dass element
genau fünfmal wiederholt wird. %b
steht für einen Binärwert.
7.1 Grundstruktur
format = RIFF-header image-header image-stream
RIFF-header = %s"RIFF" 4OCTET %s"WEBPVP8L" 4OCTET
image-header = %x2F image-size alpha-is-used version
image-size = 14BIT 14BIT ; width - 1, height - 1
alpha-is-used = 1BIT
version = 3BIT ; 0
image-stream = optional-transform spatially-coded-image
7.2 Struktur von Transformationen
optional-transform = (%b1 transform optional-transform) / %b0
transform = predictor-tx / color-tx / subtract-green-tx
transform =/ color-indexing-tx
predictor-tx = %b00 predictor-image
predictor-image = 3BIT ; sub-pixel code
entropy-coded-image
color-tx = %b01 color-image
color-image = 3BIT ; sub-pixel code
entropy-coded-image
subtract-green-tx = %b10
color-indexing-tx = %b11 color-indexing-image
color-indexing-image = 8BIT ; color count
entropy-coded-image
7.3 Struktur der Bilddaten
spatially-coded-image = color-cache-info meta-prefix data
entropy-coded-image = color-cache-info data
color-cache-info = %b0
color-cache-info =/ (%b1 4BIT) ; 1 followed by color cache size
meta-prefix = %b0 / (%b1 entropy-image)
data = prefix-codes lz77-coded-image
entropy-image = 3BIT ; subsample value
entropy-coded-image
prefix-codes = prefix-code-group *prefix-codes
prefix-code-group =
5prefix-code ; See "Interpretation of Meta Prefix Codes" to
; understand what each of these five prefix
; codes are for.
prefix-code = simple-prefix-code / normal-prefix-code
simple-prefix-code = ; see "Simple Code Length Code" for details
normal-prefix-code = ; see "Normal Code Length Code" for details
lz77-coded-image =
*((argb-pixel / lz77-copy / color-cache-code) lz77-coded-image)
Hier ist eine mögliche Beispielsequenz:
RIFF-header image-size %b1 subtract-green-tx
%b1 predictor-tx %b0 color-cache-info
%b0 prefix-codes lz77-coded-image