Dr. Jyrki Alakuijala, Google, Inc. 9.03.2023
Streszczenie
WebP bezstratny to format obrazu do bezstratnej kompresji obrazów ARGB. format bezstratny przechowuje i przywraca dokładnie wartości pikseli, łącznie z dla w pełni przezroczystych pikseli. Uniwersalny algorytm sekwencyjny kompresja danych (LZ77), kodowanie prefiksu i pamięć podręczna kolorów są wykorzystywane do lub kompresję danych zbiorczych. Dekodowanie działa szybciej niż w przypadku formatu PNG oraz o 25% gęstszej kompresji niż można osiągnąć za pomocą obecnie stosowanego formatu PNG.
1 Wstęp
Ten dokument opisuje skompresowaną reprezentację skompresowanych danych w formacie bezstratnym WebP . Jego zadaniem jest szczegółowe omówienie kodera bezstratnego WebP oraz jak używać dekodera.
W tym dokumencie szeroko zastosowaliśmy składnię w języku programowania C, aby opisać
w strumieniu bitów, z założeniem, że istnieje funkcja odczytu bitów,
ReadBits(n)
Bajty są odczytywane w naturalnej kolejności strumienia zawierającego
i bity każdego bajtu są odczytywane w kolejności od najmniej istotnej wartości. Kiedy
jednocześnie wiele bitów, liczba całkowita jest tworzona na podstawie
oryginalne dane w oryginalnej kolejności. Najważniejsze bity zwróconego
to także najbardziej istotne bity oryginalnych danych. Dlatego
instrukcja
b = ReadBits(2);
jest równoważne z 2 poniższymi stwierdzeniami:
b = ReadBits(1);
b |= ReadBits(1) << 1;
Zakładamy, że każdy składnik koloru, czyli alfa, czerwony, niebieski i zielony, jest jest reprezentowany przez 8-bitowy bajt. Odpowiedni typ definiujemy jako uint8. O cały piksel ARGB jest reprezentowany przez typ o nazwie uint32, który jest nieoznaczonym znakiem składającej się z 32 bitów. W kodzie pokazującym działanie funkcji przekształceń, wartości te są kodowane w tych bitach: alfa w bitach 31..24, czerwony w bitach 23..16, zielony w bitach 15..8 i niebieski w bitach 7..0; jednak implementacje formatu mogą swobodnie wykorzystywać wewnętrznie inne podmioty.
Ogólnie mówiąc, obraz bezstratny WebP zawiera dane nagłówka, informacje przekształcające dane obrazu. Nagłówki zawierają szerokość i wysokość obrazu. WebP bezstratnego obrazu bezstratnego, który może przejść 4 rodzaje przekształceń, zanim zostanie zakodowana entropia. Informacje o przekształceniu w strumieniu bitowym zawierają dane wymagane do zastosowania odpowiednich przekształceń odwrotnych.
2 Nazewnictwo
- ARGB,
- Wartość w pikselach składająca się z wartości alfa, czerwonego, zielonego i niebieskiego.
- Obraz ARGB
- Dwuwymiarowa tablica zawierająca piksele ARGB.
- pamięć podręczna kolorów
- Mała tablica z adresem haszowym do przechowywania ostatnio używanych kolorów można je wycofać przy użyciu krótszych kodów.
- obraz indeksowania kolorów
- Jednowymiarowy obraz kolorów, który można zindeksować za pomocą małej liczby całkowitej (do 256 w formacie bezstratnym WebP).
- obraz przekształcenia koloru
- Dwuwymiarowy obraz podrozdzielczości, który zawiera dane o korelacjach kolorów.
- mapowanie odległości
- Zmienia odległości LZ77, by mieć jak najmniejsze wartości w pikselach dwuwymiarowa bliskość.
- obraz entropii
- Dwuwymiarowy obraz podrozdzielczości wskazujący, które kodowanie entropijne powinno w odpowiednim kwadratie na obrazie, czyli każdy piksel jest meta kod prefiksu.
- LZ77
- Oparty na słowniku algorytm kompresji okien przesuwanych, który generuje lub opisuje je jako sekwencje wcześniejszych symboli.
- kod prefiksu meta
- Mała liczba całkowita (do 16 bitów), która indeksuje element w prefiksie meta tabeli.
- obraz prognozy
- Dwuwymiarowy obraz podrozdzielczości wskazujący, który prognozator przestrzenny jest w konkretnym kwadracie na obrazie.
- kod prefiksu
- Klasyczny sposób kodowania entropijnego, w którym używa się mniejszej liczby bitów aby otrzymywać je częściej.
- kodowanie prefiksu
- Sposób na entropię kodu na większe liczby całkowite, który koduje kilka bitów liczby całkowitej przy użyciu kodu entropii, a pozostałe bity są kodowane w postaci nieprzetworzonej. Dzięki temu opisy kodów entropii są stosunkowo krótkie, nawet jeśli zakres symboli jest duży.
- kolejność skanowania
- Kolejność przetwarzania w pikselach (od lewej do prawej i od góry do dołu), zaczynając do piksela u góry po lewej stronie. Po zakończeniu wiersza przejdź od w lewej kolumnie następnego wiersza.
3 nagłówek RIFF
Na początku nagłówka znajduje się kontener RIFF. Są to: kolejne 21 bajtów:
- Ciąg „RIFF”.
- Małych końców, 32-bitowa wartość długości fragmentu, która stanowi cały rozmiar fragmentu kontrolowanego przez nagłówek RIFF. Normalnie to równa się rozmiar ładunku (rozmiar pliku minus 8 bajtów: 4 bajty dla pliku „RIFF” i 4 bajty na przechowywanie samej wartości).
- Ciąg tekstowy „WEBP” (Nazwa kontenera RIFF).
- Ciąg znaków „VP8L” (FourCC w przypadku danych obrazów w formacie bezstratnym).
- 32-bitowa liczba bajtów w formacie 32-bitowym, strumienia bezstratnego.
- Podpis 1-bajtowy 0x2f.
Pierwsze 28 bitów strumienia bitowego określa szerokość i wysokość obrazu. Szerokość i wysokość są dekodowane w postaci 14-bitowych liczb całkowitych w ten sposób:
int image_width = ReadBits(14) + 1;
int image_height = ReadBits(14) + 1;
14-bitowa precyzja szerokości i wysokości obrazu ogranicza maksymalny rozmiar Bezstratny obraz WebP do 16 384 × 16384 pikseli.
Bit alpha_is_used to tylko wskazówka i nie powinien wpływać na dekodowanie. Powinna zostanie ustawiona na 0, jeśli wszystkie wartości alfa na obrazie to 255, a w przeciwnym razie na 1.
int alpha_is_used = ReadBits(1);
Wartość version_number to 3-bitowy kod, który musi mieć wartość 0. Każda inna wartość powinna być traktowane jako błąd.
int version_number = ReadBits(3);
4 przekształcenia
Przekształcenia to odwracalne modyfikacje danych obrazu, które mogą zmniejszać pozostałej entropii symbolicznej przez modelowanie korelacji przestrzennych i kolorów. Ta może zmniejszyć gęstość końcowej kompresji.
Obraz może być poddawany 4 rodzajom przekształceń. Wartość 1 bitu oznacza wystąpienia transformacji. Każdego przekształcenia można użyć tylko raz. przekształcenia są używane tylko w przypadku obrazów ARGB głównego poziomu; obrazy w podrozdzielczości (obraz przekształcenia kolorów, obraz entropii i obraz prognozy) nie mają przekształceń, a nie nawet 0 bitu wskazującego koniec przekształceń.
Zwykle koder używa tych przekształceń w celu zmniejszenia entropii Shannona. na obrazie szczątkowym. Dane dotyczące przekształcenia można również ustalić na podstawie entropii do ich minimalizacji.
while (ReadBits(1)) { // Transform present.
// Decode transform type.
enum TransformType transform_type = ReadBits(2);
// Decode transform data.
...
}
// Decode actual image data (Section 5).
Jeśli jest dostępne przekształcenie, kolejne 2 bity określają typ przekształcenia. Istnieją 4 typy przekształceń.
enum TransformType {
PREDICTOR_TRANSFORM = 0,
COLOR_TRANSFORM = 1,
SUBTRACT_GREEN_TRANSFORM = 2,
COLOR_INDEXING_TRANSFORM = 3,
};
Po typie przekształcenia znajdują się dane. Przekształcanie danych zawiera informacje wymagane do zastosowania przekształcenia odwrotnego i zależą od typ przekształcenia. Przekształcenia odwrotne są stosowane w odwrotnej kolejności: są odczytywane ze strumienia bitowego, czyli od ostatniego.
Opisujemy dane przekształceniowe w przypadku różnych typów.
4.1 Przekształcenie prognozujące
Transformer prognozowania może pomóc w zmniejszeniu entropii przez wykorzystanie faktów że sąsiednie piksele są często ze sobą skorelowane. W przekształceniu prognozy bieżąca wartość pikseli jest przewidywana na podstawie zdekodowanych pikseli (w linii skanowania kolejność), a kodowana jest tylko wartość rezydualna (rzeczywista – prognozowana). Zieleń komponentu piksela określa, który z 14 prognoz jest używany w konkretnego bloku obrazu ARGB. Tryb prognozowania określa typ do użycia z prognozą. Dzielimy obraz na kwadraty, a wszystkie piksele w korzystają z tego samego trybu prognozowania.
Pierwsze 3 bity danych prognozy określają szerokość i wysokość bloku w liczbie. z większą liczbą bitów.
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);
Dane przekształcenia zawierają tryb prognozowania dla każdego bloku obrazu. it
to obraz w podrozdzielczości, na którym zielony komponent piksela określa, który
tych 14 prognoz jest używany dla wszystkich block_width * block_height
pikseli w obrębie
konkretnego bloku obrazu ARGB. Ten obraz w podrozdzielczości jest zakodowany za pomocą
tych samych technik opisanych w rozdziale 5.
Liczba kolumn blokowych (transform_width
) jest używana w wymiarze dwuwymiarowym
indeksowanie. W przypadku piksela (x, y) można obliczyć odpowiedni blok filtra
adres według:
int block_index = (y >> size_bits) * transform_width +
(x >> size_bits);
Istnieje 14 różnych trybów prognozowania. W każdym trybie prognozowania bieżąca wartość piksela jest przewidywana na podstawie co najmniej jednego sąsiedniego piksela, którego wartości są już znane.
Wybraliśmy sąsiednie piksele (TL, T, TR i L) bieżącego piksela (P) jako następujące:
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
gdzie TL oznacza lewy górny róg, T oznacza górny róg, TR oznacza prawy górny róg, a L oznacza lewy górny róg. Na czas prognozowania wartości dla P, dla wszystkich pikseli O, TL, T, TR i L, i piksel P i wszystkie piksele X są nieznane.
Biorąc pod uwagę sąsiednie piksele poprzedzające, różne tryby prognozowania są w następujący sposób.
Tryb | Prognozowana wartość każdego kanału bieżącego piksela |
---|---|
0 | 0xff000000 (reprezentuje czarny kolor w ARGB) |
1 | L |
2 | T |
3 | lirach tureckich |
4 | kierownik zespołu |
5 | Średnia2(Średnia2(L; TR); T) |
6 | Średnia2(L; TL) |
7 | Średnia2(L; T) |
8 | Średnia2(TL; T) |
9 | Średnia2(T; TR) |
10 | Średnia2(L; TL); Średnia2(T; TR)) |
11 | Wybierz(L; T; TL) |
12 | ClampAddSubtractFull(L, T, TL) |
13 | ClampAddSubtractHalf(Average2(L, T), TL) |
W przypadku każdego komponentu ARGB Average2
jest zdefiniowany w ten sposób:
uint8 Average2(uint8 a, uint8 b) {
return (a + b) / 2;
}
Formuła „Wybierz” jest zdefiniowany w ten sposób:
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;
}
}
Wykonywane są funkcje ClampAddSubtractFull
i ClampAddSubtractHalf
dla każdego komponentu ARGB w ten sposób:
// 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);
}
W przypadku niektórych pikseli obramowania obowiązują specjalne zasady obsługi. Jeśli występuje niezależnie od trybu [0..13] dla tych pikseli, przewidywana wartość dla skrajnego lewego piksela obrazu to 0xff000000, wszystkie piksele w górnym wierszu mają rozmiar L, a wszystkie piksele w pierwszej kolumnie po lewej stronie T-pixel.
Adresowanie piksela TR dla pikseli w pierwszej kolumnie po prawej stronie to: coś wyjątkowego. Piksele w pierwszej kolumnie po prawej stronie są prognozowane przy użyciu trybów [0..13] tak jak piksele niewidoczne na obramowaniu, ale skrajny lewy piksel na w tym samym wierszu co bieżący piksel jest używany jako piksel TR.
Ostateczną wartość piksela uzyskuje się przez dodanie każdego kanału prognozowanej wartości do zakodowanej wartości rezydualnej.
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 Przekształcenie kolorów
Celem przekształcenia kolorów jest dekorowanie wartości R, G i B każdego z nich piksel. Transformacja koloru zachowuje zieloną wartość (G) w niezmienionej postaci, przekształca czerwonego (R) na podstawie wartości zielonej, a na tej podstawie przekształca wartość niebieskiej (B) na zielonej wartości, a potem na wartości czerwonej.
Tak jak w przypadku przekształcenia prognozy, najpierw obraz jest dzielony na i ten sam tryb przekształcania jest stosowany dla wszystkich pikseli w danym bloku. Dla: w każdym bloku są trzy rodzaje elementów przekształcania kolorów.
typedef struct {
uint8 green_to_red;
uint8 green_to_blue;
uint8 red_to_blue;
} ColorTransformElement;
Rzeczywiste przekształcenie koloru jest wykonywane przez zdefiniowanie delta przekształcenia koloru.
delta przekształcenia koloru zależy od wartości ColorTransformElement
, która jest taka sama
wszystkich pikseli w danym bloku. Wartość delta jest odejmowana w okresie
przekształcenia kolorów. Odwrotne przekształcenie kolorów dodaje tylko te delta.
Funkcja przekształcania kolorów jest zdefiniowana w ten sposób:
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;
}
Wartość ColorTransformDelta
jest obliczana z użyciem 8-bitowej liczby całkowitej ze znakiem, która reprezentuje
Stały, 3,5-punktowy numer i 8-bitowy kanał kolorów RGB (c) [-128..127]
i jest zdefiniowany w ten sposób:
int8 ColorTransformDelta(int8 t, int8 c) {
return (t * c) >> 5;
}
Konwersja z 8-bitowej reprezentacji bez znaku (uint8) na 8-bitową reprezentację ze znakiem
Przed wywołaniem funkcji ColorTransformDelta()
wymagana jest wartość 1 (int8). Wartość ze znakiem
powinna być interpretowana jako 8-bitowa liczba uzupełniająca dwóch (czyli zakres uint8)
[128..255] jest mapowany na zakres [-128..-1] swojej przekonwertowanej wartości int8).
Mnożenie należy wykonać z większą precyzją (z co najmniej 16-bitowym precyzja). Właściwość rozszerzenia znaku w operacji przesunięcia nie ma znaczenia tutaj; z wyniku używanych jest tylko 8 najniższych bitów, a znak przesuwanie rozszerzeń i przesunięcie nieoznaczone są ze sobą spójne.
Opisujemy zawartość danych dotyczących przekształcenia kolorów, dzięki czemu można zastosować dekodowanie odwrotność koloru oraz przywrócenie oryginalnych wartości czerwieni i niebieskiego. pierwsze 3 bity danych przekształcenia koloru zawierają szerokość i wysokość blok obrazu w liczbie bitów, tak jak w przypadku przekształcenia prognozy:
int size_bits = ReadBits(3) + 2;
int block_width = 1 << size_bits;
int block_height = 1 << size_bits;
Pozostała część danych przekształcenia koloru zawiera: ColorTransformElement
odpowiadające poszczególnym blokom obrazu. Każdy
ColorTransformElement
'cte'
jest traktowany jako piksel na obrazie w podrozdzielczości
którego komponent alfa to 255
, komponent czerwony to cte.red_to_blue
, zielony
komponent ma wartość cte.green_to_blue
, a komponent niebieski to cte.green_to_red
.
Podczas dekodowania dekodowane są wystąpienia bloków (ColorTransformElement
)
odwrotne przekształcenie kolorów jest stosowane do wartości ARGB pikseli. Jako
że odwrotne przekształcenie kolorów polega na dodaniu mu
ColorTransformElement
wartości do czerwonego i niebieskiego kanału. Alfa i zielony
Kanały pozostają bez zmian.
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 Odejmij transformację zieloną
Odejmowanie zielonego przekształcenia odejmuje wartości zielone od wartości czerwonego i niebieskiego wartości za każdy piksel. Gdy jest dostępne to przekształcenie, dekoder musi dodać zieloną ikonę zarówno na wartości czerwone, jak i niebieskie. Brak powiązanych danych przekształcenie. Dekoder stosuje odwrotne przekształcenie w ten sposób:
void AddGreenToBlueAndRed(uint8 green, uint8 *red, uint8 *blue) {
*red = (*red + green) & 0xff;
*blue = (*blue + green) & 0xff;
}
To przekształcenie jest nadmiarowe, ponieważ można je modelować za pomocą przekształcenia koloru. ponieważ nie ma tu dodatkowych danych, odejmowanie zielonego przekształcenia może jest zakodowana przy użyciu mniejszej liczby bitów niż pełne przekształcenie kolorów.
4.4 Transformacja indeksowania kolorów
Jeśli nie ma wielu unikalnych wartości pikseli, lepszym rozwiązaniem może być utworzenie indeks kolorów i zastąp wartości pikseli indeksami tej tablicy. Kolor jest to możliwe dzięki przekształceniu indeksowania. (W kontekście technologii WebP bezstratnej nie nazywaj tego przekształceniem palety, ponieważ podobny, ale bardziej w kodowaniu bezstratnym WebP można zastosować pojęcie dynamicznego: pamięć podręczna kolorów).
Transformacja indeksowania kolorów sprawdza liczbę unikalnych wartości ARGB w . Jeśli ta liczba nie przekracza progu (256), tworzy tablicę tych ARGB, które są następnie używane do zastąpienia wartości pikseli przez odpowiedni indeks: zielony kanał pikseli jest zastępowany indeksu, wszystkie wartości alfa są ustawione na 255, a wszystkie wartości czerwonego i niebieskiego na 0.
Dane przekształcenia zawierają rozmiar tabeli kolorów i wpisy w kolorze tabeli. Dekoder odczytuje dane przekształcenia indeksowania kolorów w następujący sposób:
// 8-bit value for the color table size
int color_table_size = ReadBits(8) + 1;
Tabela kolorów jest przechowywana z użyciem tego formatu. Tabela kolorów
można uzyskać, odczytując obraz bez nagłówka RIFF, rozmiaru
przekształca, przyjmując wysokość 1 piksela i szerokość color_table_size
.
Tabela kolorów jest zawsze kodowana za pomocą odejmowania w celu zmniejszenia entropii obrazu. Delty
kolorów palety mają zwykle znacznie mniejszą entropię niż kolory
się, co znacznie oszczędza mniejsze obrazy. Przy dekodowaniu
każdy końcowy kolor w tabeli kolorów można uzyskać, dodając poprzedni kolor
wartości składowych koloru przez każdy komponent ARGB oddzielnie i z przechowywaniem najmniejszych wartości
8 bitów wyniku.
Odwrotne przekształcenie obrazu polega na zastąpieniu wartości pikseli (co to indeksy do tabeli kolorów) z rzeczywistymi wartościami z tabeli kolorów. Indeksowanie powstaje na podstawie zielonego komponentu koloru ARGB.
// Inverse transform
argb = color_table[GREEN(argb)];
Jeśli indeks jest równy lub większy od color_table_size
, wartość koloru albo
powinna mieć wartość 0x00000000 (przezroczysta czerń).
Jeśli tabela kolorów jest mała (maksymalnie 16 kolorów lub mniej), kilka pikseli są połączone w jeden piksel. Zestaw pikseli obejmuje kilka pikseli (2, 4 lub 8) na jeden piksel, co odpowiednio zmniejszy szerokość obrazu. Pikselowy łączenie w grupy pozwala na bardziej efektywne wspólne kodowanie entropii rozkładu i przylegają do siebie piksele, co przydaje się w przypadku kodowania arytmetycznego. , ale można go użyć tylko wtedy, gdy liczba niepowtarzalnych wartości jest nie większa niż 16.
color_table_size
określa, ile pikseli mają zostać połączone:
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
ma wartość 0, 1, 2 lub 3. Wartość 0 oznacza brak piksela
dla obrazu. Wartość 1 oznacza, że 2 piksele są
łącznie, a każdy piksel ma zakres [0..15]. Wartość 2 oznacza, że
przy czym każdy piksel ma zakres [0..3]. Wartość 3
oznacza, że połączonych jest osiem pikseli, a każdy piksel ma zakres [0..1],
czyli wartość binarną.
Wartości są spakowane do komponentu zielonego w taki sposób:
width_bits
= 1: dla każdej wartości x, gdzie x Љ 0 (mod 2), oznacza kolor zielony jest umieszczona w 4 najmniej istotnych bitach parametru wartości zielonej w miejscu x / 2, a zielona wartość x + 1 4 najważniejsze bity wartości zielonej w miejscu x / 2.width_bits
= 2: dla każdej wartości x, gdzie x OFFER 0 (mod 4), zielony pod względem x jest umieszczona w 2 najmniej istotnych bitach parametru zielone wartości x / 4, a zielone od x + 1 do x + 3 są umiejscowione w do ważniejszych bitów wartości zielonej w x / 4.width_bits
= 3: dla każdej wartości x, gdzie x Љ 0 (mod 8), oznacza kolor zielony znajduje się przy najmniejszym istotnym bitzie zielonego x / 8, a zielone wartości od x + 1 do x + 7 są ułożone w kolejności do ważniejszych bitów wartości zielonej w x / 8.
Po przeczytaniu tego przekształcenia wartość image_width
jest próbkowana według parametru width_bits
. Ten
wpływa na rozmiar kolejnych przekształceń. Nowy rozmiar można obliczyć za pomocą
DIV_ROUND_UP
zgodnie z definicją wcześniej.
image_width = DIV_ROUND_UP(image_width, 1 << width_bits);
5 Dane graficzne
Dane obrazu to tablica wartości pikseli w kolejności wierszy skanowania.
5.1 Role danych obrazów
Danych obrazów używamy w ramach 5 różnych ról:
- Obraz ARGB: zapisuje rzeczywiste piksele obrazu.
- Obraz entropii: zapisuje kody prefiksów meta (zobacz „Dekodowanie kodów prefiksów meta”).
- Obraz prognozy: przechowuje metadane przekształcenia prognozowanego (patrz „Przekształcenie prognozujące”).
- Obraz przekształcenia koloru: utworzony przez wartość
ColorTransformElement
(zdefiniowany w funkcji „Przekształcenie kolorów”) dla różnych brył obrazu. - Obraz indeksowania kolorów: tablica o rozmiarze
color_table_size
(do 256 ARGB) wartości), w których są przechowywane metadane do przekształcenia indeksowania kolorów (patrz „Przekształcenie indeksowania kolorów”).
5.2 Kodowanie danych obrazu
Kodowanie danych obrazu jest niezależne od jego roli.
Obraz jest najpierw dzielony na zbiór bloków o stałym rozmiarze (zwykle o wymiarach 16 x 16) bloki). Każdy z tych bloków jest modelowany za pomocą własnych kodów entropii. Oprócz tego: kilka bloków może mieć ten sam kod entropii.
Uzasadnienie: przechowywanie kodu entropii wiąże się z kosztami. Koszt ten można zminimalizować jeśli statystycznie podobne bloki mają wspólny kod entropii, przez co ten kod jest przechowywany tylko raz. Koder może na przykład znaleźć podobne bloki przez grupowanie ich za pomocą ich właściwości statystycznych lub przez wielokrotne łączenie pary losowych par wybranych klastrów, gdy zmniejsza to łączną liczbę bitów niezbędnych do zakodowania zdjęcia.
Każdy piksel jest kodowany za pomocą jednej z trzech możliwych metod:
- Literały zakodowane z prefiksem: każdy kanał (zielony, czerwony, niebieski i alfa) jest kodowana entropią niezależnie.
- Odwołanie wsteczne LZ77: sekwencja pikseli jest kopiowana z innego miejsca w zdjęcia.
- Kod pamięci podręcznej kolorów: użycie krótkiego zwielokrotnienia kodu haszującego (pamięć podręczna kolorów) indeksu ) ostatnio oglądanego koloru.
W poniższych podsekcjach szczegółowo opisujemy każdy z tych sposobów.
5.2.1 Literały zakodowane z prefiksem
Piksel jest zapisywany jako poprzedzone prefiksem wartości kolorów zielonego, czerwonego, niebieskiego i alfa (w to zamówienie). Zobacz artykuł 6.2.3, aby dowiedzieć się więcej. .
5.2.2 LZ77 Odniesienia wsteczne
Odwołania wsteczne to krotki określające długość i kod odległości:
- Wartość wskazuje, ile pikseli w kolejności wierszy skanowania ma zostać skopiowane.
- Kod odległości to liczba określająca pozycję piksel, z którego mają zostać skopiowane piksele. Dokładne mapowanie opisane poniżej.
Wartości długości i odległości są przechowywane za pomocą kodowania z prefiksem LZ77.
Kodowanie z prefiksem LZ77 dzieli duże liczby całkowite na 2 części: prefiks kod i dodatkowe bity. Kod prefiksu jest przechowywany za pomocą kodu entropii, a dodatkowe bity są przechowywane w niezmienionej formie (bez kodu entropii).
Uzasadnienie: to podejście zmniejsza wymagania dotyczące przechowywania entropii. w kodzie. Duże wartości są zwykle rzadkie, więc dodatkowe bity są używane kilka wartości. Takie podejście zapewnia lepszą kompresję i ogólne.
Poniższa tabela zawiera kody prefiksów i dodatkowe bity używane do przechowywania różnych zakresów wartości.
Zakres wartości | Kod prefiksu | Dodatkowe bity |
---|---|---|
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... | 7 | 2 |
… | ... | … |
3072..4096 | 23 | 10 |
… | ... | … |
524289..786432 | 38 | 18 |
786433..1048576 | 39 | 18 |
Pseudokod do uzyskania wartości (długości lub odległości) z kodu prefiksu to następujące:
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;
Wyznaczanie odległości
Jak wspomnieliśmy wcześniej, kod odległości jest liczbą wskazującą pozycję widziany wcześniej piksel, z którego mają zostać skopiowane piksele. Ta podsekcja określa mapowanie między kodem odległości a pozycją poprzedniego piksel.
Kody odległości większe niż 120 wskazują odległość w pikselach w kolejności wierszy skanowania. przesunięcie o 120.
Najmniejsze kody odległości [1..120] są specjalne i są zarezerwowane dla zamknięcia w okolicy bieżącego piksela. Ta okolica składa się z 120 pikseli:
- Piksele znajdujące się od 1 do 7 wierszy powyżej bieżącego piksela i mające maksymalnie 8 kolumn.
po lewej lub maksymalnie 7 kolumn po prawej stronie bieżącego piksela. [Łącznie
takie piksele =
7 * (8 + 1 + 7) = 112
]. - Maksymalna liczba pikseli, które są w tym samym wierszu co bieżący piksel, wynosi maksymalnie 8
kolumn po lewej stronie bieżącego piksela. [
8
takich pikseli].
Mapowanie między kodem odległości distance_code
a sąsiednim pikselem
przesunięcie (xi, yi)
wygląda tak:
(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)
Na przykład kod odległości 1
wskazuje przesunięcie wynoszące (0, 1)
dla
sąsiadujący piksel, czyli piksel powyżej bieżącego (piksela 0
różnica w kierunku osi X i 1 pikselowa różnica w kierunku osi Y).
Podobnie kod odległości 3
wskazuje lewy górny piksel.
Dekoder może przekonwertować kod odległości distance_code
na kolejność skanowania wiersza
odległość dist
w następujący sposób:
(xi, yi) = distance_map[distance_code - 1]
dist = xi + yi * image_width
if (dist < 1) {
dist = 1
}
gdzie distance_map
to mapowanie podane powyżej, a image_width
to szerokość
obrazu w pikselach.
5.2.3 Kodowanie z pamięci podręcznej kolorów
Pamięć podręczna kolorów zawiera zestaw kolorów, które były ostatnio używane w obrazie.
Uzasadnienie: dzięki temu ostatnio używane kolory mogą być nazywane niż ich emitowanie przy użyciu dwóch pozostałych metod (opisanych w 5.2.1 i 5.2.2).
Kody pamięci podręcznej kolorów są przechowywane w następujący sposób. Po pierwsze, mamy 1-bitową wartość, wskazuje, czy używana jest pamięć podręczna kolorów. Jeśli ten bit ma wartość 0, kody pamięci podręcznej kolorów nie są wyświetlane. i nie są przesyłane w kodzie prefiksu, który dekoduje zielony symboli i kodów długości. Jeśli jednak ten bit ma wartość 1, pamięć podręczna kolorów rozmiar jest odczytywany dalej:
int color_cache_code_bits = ReadBits(4);
int color_cache_size = 1 << color_cache_code_bits;
color_cache_code_bits
określa rozmiar pamięci podręcznej kolorów (1 <<
color_cache_code_bits
). Zakres dozwolonych wartości dla
color_cache_code_bits
to [1..11]. Zgodne dekodery muszą wskazywać
uszkodzonego strumienia bitowego dla innych wartości.
Pamięć podręczna kolorów to tablica o rozmiarze color_cache_size
. Każdy wpis zawiera 1 ARGB
koloru. Kolory są wyszukiwane przez indeksowanie przez (0x1e35a7bd * color) >> (32 -
color_cache_code_bits)
. W pamięci podręcznej kolorów wykonywane jest tylko jedno wyszukiwanie; nie ma
rozwiązywanie konfliktów.
Na początku dekodowania lub kodowania obrazu wszystkie wpisy we wszystkich kolorach wartości pamięci podręcznej są ustawione na zero. Kod z pamięci podręcznej koloru jest konwertowany na ten kolor przy czas dekodowania. Stan pamięci podręcznej kolorów jest utrzymywany przez wstawienie każdego niezależnie od tego, czy jest on generowany przez odwołanie wsteczne, czy jako literały, do pamięci podręcznej w kolejności, w jakiej pojawiają się w strumieniu.
Kod entropii 6
6.1 Omówienie
Większość danych jest kodowana z wykorzystaniem kanonicznego kodu prefiksu. Dlatego też są przesyłane, wysyłając długości kodów z prefiksami: zamiast rzeczywistych kodów prefiksów.
W szczególności format wykorzystuje kodowanie prefiksów wariantów przestrzennych. W innym słowa, poszczególne bloki obrazu mogą opisywać różną entropię kodami.
Uzasadnienie: różne obszary obrazu mogą mieć różne cechy. Zezwolenie na stosowanie różnych kodów entropii zapewnia więc większą elastyczność i potencjalnie lepszą kompresję.
6.2 Szczegóły
Zakodowane dane obrazu składają się z kilku części:
- Dekodowanie i tworzenie kodów prefiksów.
- Metakody prefiksów.
- Dane obrazów zakodowane entropią.
Dla każdego piksela (x, y) istnieje zestaw pięciu kodów prefiksów powiązanych z . Te kody (w kolejności bitów strumieniowych):
- Kod prefiksu 1: używany w przypadku kanału zielonego, długości odwołania wstecznego i pamięci podręcznej kolorów.
- Kod prefiksu 2, #3 i 4: używany w przypadku kanałów czerwonego, niebieskiego i alfa, .
- Kod prefiksu 5: używany do określania odległości w odniesieniu do tyłu.
Od tej pory ten zestaw nazywamy grupą kodu prefiksu.
6.2.1 Dekodowanie i tworzenie kodów prefiksów
Ta sekcja zawiera informacje na temat odczytywania długości kodu prefiksu z strumienia bitowego.
Długości kodów prefiksów mogą być kodowane na dwa sposoby. Użyta metoda jest określona jako wartość 1-bitową.
- Jeśli ten bit ma wartość 1, jest to prosty kod długości kodu.
- Jeśli ten bit ma wartość 0, jest to kod o normalnej długości kodu.
W obu przypadkach mogą istnieć nieużywane długości kodu, które nadal są częścią tagu . Może to być nieskuteczne, ale jest dozwolone przez format. Opisane drzewo musi być kompletnym drzewem binarnym. uważane za kompletne drzewo binarne i można je zakodować za pomocą prostego lub zwykłej długości kodu. Przy kodowaniu pojedynczego liścia przy użyciu kodu o normalnej długości kodu, ale tylko jednej długości kodu liczone są zera, a wartość węzła pojedynczego liścia jest oznaczona długością równą 1 – nawet jeśli nie zużywane są bity, gdy używane jest to jednoliściowe drzewo węzła.
Prosty kod długości
Ten wariant jest używany w szczególnych przypadkach, gdy występują tylko 1 lub 2 symboly prefiksu.
zakres [0..255] o długości kodu 1
. Pozostałe długości kodu prefiksu
domyślnie zera.
Pierwszy bit określa liczbę symboli:
int num_symbols = ReadBits(1) + 1;
Poniżej przedstawiono wartości symboli.
Pierwszy symbol jest zakodowany za pomocą 1 lub 8 bitów, w zależności od wartości
is_first_8bits
Zakres to odpowiednio [0..1] lub [0..255]. Druga
(jeśli występuje) zawsze zakłada się, że mieści się on w zakresie [0..255] i jest zakodowany
przy użyciu 8 bitów.
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;
}
Symbole powinny być różne. Symbole mogą się powtarzać, ale nieefektywne.
Uwaga: innym szczególnym przypadkiem jest sytuacja, w której wszystkie długości kodu prefiksu mają wartość 0 (kod
pusty kod prefiksu). Na przykład kod prefiksu odległości może być pusty, jeśli
nie ma odniesień wstecznych. Podobnie kody alfa, czerwonego i czerwonego
kolor niebieski może być pusty, jeśli zostaną wygenerowane wszystkie piksele w tym samym kodzie prefiksu meta
z pamięci podręcznej kolorów. W tym przypadku nie trzeba się nią zajmować, bo
puste kody prefiksów mogą być kodowane jako zawierające pojedynczy symbol 0
.
Kod normalnej długości kodu
Długości kodu prefiksu mieszczą się w 8 bitach i są odczytywane w następujący sposób.
Najpierw num_code_lengths
określa liczbę długości kodu.
int num_code_lengths = 4 + ReadBits(4);
Długości kodów są kodowane za pomocą kodów prefiksów. kod niższego poziomu
długości, code_length_code_lengths
, muszą najpierw zostać przeczytane. Pozostałe
code_length_code_lengths
(zgodnie z zamówieniem w kCodeLengthCodeOrder
)
wynosi zero.
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);
}
Następnie, jeśli ReadBits(1) == 0
, maksymalna liczba różnych symboli do odczytu
(max_symbol
) dla każdego typu symbolu (A, R, G, B i odległość) jest ustawiony na
wielkość alfabetu:
- Kanał G: 256 + 24 +
color_cache_size
- Inne literały (A, R i B): 256
- Kod odległości: 40
W przeciwnym razie jest ona definiowana w ten sposób:
int length_nbits = 2 + 2 * ReadBits(3);
int max_symbol = 2 + ReadBits(length_nbits);
Jeśli max_symbol
jest większy niż rozmiar alfabetu dla danego typu symbolu,
Parametr bitstream jest nieprawidłowy.
Następnie na podstawie code_length_code_lengths
jest tworzona tabela prefiksów i używana do odczytu
do max_symbol
długości kodu.
- Kod [0..15] wskazuje dosłowne długości kodów.
- Wartość 0 oznacza, że nie zakodowano żadnych symboli.
- Wartości [1..15] wskazują liczbę bitów odpowiedniego kodu.
- Kod 16 powtarza poprzednią wartość niezerową [3..6] razy, czyli
3 + ReadBits(2)
razy. Jeśli kod 16 jest używany przed znakiem innym niż 0 zostaje wyemitowana wartość 8, powtórzona. - Kod 17 generuje serię zer o długości [3..10], czyli
3 + ReadBits(3)
razy. - Kod 18 tworzy serię zer o długości [11..138], czyli
11 + ReadBits(7)
razy.
Po odczytaniu długości kodu prefiks dla każdego typu symboli (A, R, G, B, odległość) powstaje przy użyciu odpowiednich rozmiarów alfabetu.
Kod normalnej długości kodu musi zakodować pełne drzewo decyzyjne, czyli sumę
2 ^ (-length)
w przypadku wszystkich kodów innych niż 0 musi mieć dokładnie 1. Istnieją jednak
wyjątek od tej reguły: drzewo węzła jednolitego, gdzie węzeł liścia
jest oznaczona wartością 1, a inne wartości to 0 s.
6.2.2 Dekodowanie kodów prefiksów meta
Jak już wspomnieliśmy, format pozwala na używanie różnych kodów prefiksów różne bloki obrazu. Kody metaprefiksów to indeksy identyfikujące które kodów prefiksów używanych w różnych częściach obrazu.
Kodów metaprefiksów można używać tylko wtedy, gdy obraz jest używany w role obrazu ARGB.
Metaprefiksy mogą mieć 2 możliwości (1-bitowe) wartość:
- Jeśli ten bit ma wartość zero, wszędzie w argumencie jest używany tylko jeden kod prefiksu meta zdjęcia. Żadne dane nie będą przechowywane.
- Jeśli ten bit to 1, obraz używa wielu metaprefiksów. Te metadane kody prefiksów są przechowywane jako obrazy entropii (opisane poniżej).
Czerwone i zielone komponenty piksela określają 16-bitowy kod metaprefiksu używany w konkretnego bloku obrazu ARGB.
Obraz entropii
Obraz entropii określa, które kody prefiksów są używane w różnych częściach kodu .
Pierwsze 3 bity zawierają wartość prefix_bits
. Wymiary entropii
obraz pochodzi z prefix_bits
:
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);
gdzie DIV_ROUND_UP
jest określone wcześniej.
Następne bity zawierają obraz entropii o szerokości prefix_image_width
i wysokości
prefix_image_height
Interpretacja kodów prefiksów meta
Liczbę grup kodów prefiksów w obrazie ARGB można uzyskać, znajdując największy kod metaprefiksu z obrazu entropii:
int num_prefix_groups = max(entropy image) + 1;
gdzie max(entropy image)
oznacza największy kod prefiksu przechowywany w
obrazu entropii.
Każda grupa kodów prefiksów zawiera pięć kodów prefiksów, więc łączna liczba prefiksów Kody to:
int num_prefix_codes = 5 * num_prefix_groups;
Biorąc pod uwagę piksel (x, y) na obrazie ARGB, możemy uzyskać odpowiedni prefiks należy używać w następujący sposób:
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];
w którym zakładamy, że ma strukturę PrefixCodeGroup
, która
reprezentuje zestaw pięciu kodów prefiksów. prefix_code_groups
jest również tablicą funkcji
PrefixCodeGroup
(rozmiaru num_prefix_groups
).
Dekoder używa następnie grupy kodów prefiksu prefix_group
do dekodowania piksela
(x, y), jak wyjaśniono w części „Dekodowanie obrazu zakodowanego entropią
Dane”.
6.2.3 Dekodowanie danych obrazów zakodowanych entropią
W bieżącej pozycji (x, y) na obrazie dekoder najpierw identyfikuje odpowiedniej grupy kodów prefiksów (jak wyjaśniono w ostatniej sekcji). Biorąc pod uwagę grupę kodów prefiksu, piksel jest odczytywany i dekodowany w ten sposób.
Następnie odczytaj symbol S ze strumienia bitowego przy użyciu kodu prefiksu nr 1. Zwróć uwagę, że S jest
dowolna liczba całkowita z zakresu od 0
do
(256 + 24 +
color_cache_size
- 1)
.
Interpretacja S zależy od jego wartości:
- Jeśli S < 256
- Jako komponent zielony użyj S.
- Odczytaj dane ze strumienia bitowego na czerwono przy użyciu kodu prefiksu nr 2.
- Odczytuj kolor niebieski ze strumienia bitowego za pomocą kodu prefiksu 3.
- Odczytaj wersję alfa ze strumienia bitowego przy użyciu kodu prefiksu 4.
- Jeśli S >= 256 & S < 256 + 24
- Jako kodu prefiksu długości użyj kodu S-256.
- Odczytaj dodatkowe bity odpowiadające danej długości ze strumienia bitowego.
- Określ długość wstecznej L na podstawie kodu prefiksu długości oraz żeby odczytać dodatkowe informacje.
- Odczytaj kod prefiksu odległości ze strumienia bitowego za pomocą kodu prefiksu nr 5.
- Odczytuj dodatkowe bity oznaczające odległość od strumienia bitowego.
- Wyznacz odległość wsteczną D na podstawie kodu prefiksu odległości i odczytane dodatkowe informacje.
- Skopiuj piksele L (w kolejności wierszy skanowania) z sekwencji pikseli rozpoczynających się w bieżącej pozycji minus D pikseli.
- Jeśli S >= 256 + 24
- Użyj znaków S- (256 + 24) jako indeksu w pamięci podręcznej kolorów.
- Pobierz kolor ARGB z pamięci podręcznej kolorów dla tego indeksu.
7 Ogólna struktura formatu
Poniżej znajduje się omówienie formatu w rozszerzonej notacji Backusa-Naura (ABNF) RFC 5234 RFC 7405. Nie obejmują one wszystkich szczegółów. Koniec obrazu (EOI) jest domyślnie zakodowany w postaci liczby pikseli (image_width * image_height).
Pamiętaj, że *element
oznacza, że element element
może się powtarzać 0 lub więcej razy. 5element
oznacza, że element element
jest powtórzony dokładnie 5 razy. %b
to wartość binarna.
7.1 Podstawowa struktura
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 Struktura przekształceń
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 Struktura danych zdjęć
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)
Oto przykładowa sekwencja:
RIFF-header image-size %b1 subtract-green-tx
%b1 predictor-tx %b0 color-cache-info
%b0 prefix-codes lz77-coded-image