Jyrki Alakuijala, PhD, Google, Inc., 09.03.2023
Soyut
WebP kayıpsız, ARGB resimlerinin kayıpsız sıkıştırılması için kullanılan bir resim biçimidir. İlgili içeriği oluşturmak için kullanılan kayıpsız biçim, şunlar da dahil olmak üzere piksel değerlerini tam olarak depolar ve geri yükler: renk değerlerini kullanmanızı öneririz. Ardışık düzen için evrensel bir algoritma Veri sıkıştırma (LZ77), önek kodlaması ve renk önbelleği, sıkıştırılmış verilerdir. Kod çözme hızları PNG'den daha hızlı elde edilene kıyasla% 25 daha yoğun bir sıkıştırma bugünkü PNG biçiminde sunulur.
1 Giriş
Bu belgede, kayıpsız bir WebP'nin sıkıştırılmış veri temsili açıklanmaktadır görüntüsüdür. WebP kayıpsız kodlayıcı ve kod çözücü uygulaması için ayrıntılı bir referans olarak tasarlanmıştır.
Bu belgede, C programlama dili söz dizimini kullanarak
ve bitleri okumak için bir fonksiyonun mevcut olduğunu varsaymak,
ReadBits(n)
Baytlar, veri feed'i içeren akışın sırasına göre
ve her baytın bitleri en az anlamlı bit-ilk sıraya göre okunur. Zaman
birden çok bit aynı anda okunursa tam sayı,
orijinal sırasına göre düzenleyebilirsiniz. Döndürülen
tamsayılar da orijinal verilerin en önemli bitleridir. Dolayısıyla,
ifade
b = ReadBits(2);
aşağıdaki iki ifadeye eşdeğerdir:
b = ReadBits(1);
b |= ReadBits(1) << 1;
Alfa, kırmızı, mavi ve yeşil olmak üzere her bir renk bileşeninin, 8 bitlik bayt kullanılarak temsil edilir. Karşılık gelen türü uint8 olarak tanımlarız. CEVAP ARGB pikselinin tamamı, uint32 adında bir türle temsil edilir. 32 bitten oluşan tam sayı. Davranışı gösteren kodda, bu değerler, bit cinsinden şu bitlere kodlanır: bit cinsinden alfa 31..24, 23..16 bitlerinde kırmızı, 15..8 bitlerinde yeşil ve 7..0 bitlerinde mavi; ancak, biçimin uygulanmasında, şirket içinde başka bir temsil kullanmak serbesttir.
Genel olarak WebP kayıpsız resmi, başlık verilerini, dönüştürme bilgilerini ve gerçek resim verileridir. Başlıklar, resmin genişliğini ve yüksekliğini içerir. WebP kayıpsız resim, silinmeden önce dört farklı dönüşüm türünde geçebilir entropi kodlanmıştır. Bit akışındaki dönüşüm bilgileri, ilgili ters dönüşümleri uygulamak için gereklidir.
2 Nomenklatür
- ARGB
- Alfa, kırmızı, yeşil ve mavi değerlerinden oluşan bir piksel değeri.
- ARGB resmi
- ARGB pikselleri içeren iki boyutlu bir dizi.
- renk önbelleği
- Son kullanılan renklerin depolandığı, karma adresli küçük bir dizi: bunları daha kısa kodlarla hatırlayın.
- renk dizine ekleme resmi
- Küçük bir tam sayı kullanılarak dizine eklenebilen renklerin tek boyutlu görüntüsü (WebP'de kayıpsız en fazla 256).
- renk dönüştürme resmi
- Renk bileşenlerinin korelasyonlarıyla ilgili veriler içeren iki boyutlu bir alt çözünürlüklü resim.
- mesafe haritası
- LZ77 mesafelerini, pikseller için en küçük değerlere sahip olacak şekilde değiştirir yakınlık sağlar.
- entropi resmi
- Entropi kodlamasının hangi iki boyutlu alt çözünürlüklü olması gerektiğini gösteren birlikte kullanılmalıdır, yani her piksel bir meta önek kodunu ekleyin.
- LZ77
- Sözlük tabanlı bir kayan pencere sıkıştırma algoritması için veya bunları geçmiş sembollerin dizileri olarak tarif eden içerikler üretir.
- meta önek kodu
- Meta ön ekteki bir öğeyi dizine ekleyen küçük bir tam sayı (16 bit'e kadar) tablosunda gösterilir.
- Tahmin resmi
- Hangi mekansal tahmincinin olduğunu gösteren iki boyutlu alt çözünürlüklü bir görüntü nasıl kullanılacağını anlatacağım.
- önek kodu
- Daha sık kodlar için daha az bit kullanıldığı klasik bir entropi kodlama yöntemi.
- önek kodlaması
- Daha büyük tam sayıları entropi kodlamanın bir yoludur. Bu yöntemde, entropi kodu kullanılarak tam sayının birkaç biti kodlanır ve kalan bitler ham olarak kodlanır. Bu da entropi kodlarının tanımlarının ne kadar küçük olduğunu görsek bile simge aralığı geniş olduğundan emin olun.
- satır tarama sırası
- Sol üstteki pikselden başlayarak piksellerin işlenme sırası (soldan sağa ve yukarıdan aşağıya). Bir satır tamamlandıktan sonra, devam etmek için diğer satırın sol sütununa girin.
3 RIFF Başlığı
Üstbilginin başında RIFF kapsayıcısı bulunur. Bu, (21 bayt altında):
- Dize 'RIFF'.
- Yığın uzunluğunun tam boyutu olan 32 bitlik küçük son değeri kontrol edilen parçasını görebilirsiniz. Bu değer normalde yükü boyutuna eşittir (dosya boyutu eksi 8 bayt: "RIFF" tanımlayıcısı için 4 bayt ve değerin kendisini depolamak için 4 bayt).
- Dize: "WEBP" (RIFF kapsayıcı adı).
- Dize: "VP8L" (Kayıpsız kodlanmış resim verileri için dört kod).
- Veri kümesindeki bayt sayısının 32 bitlik kayıpsız akış sağlar.
- 1 baytlık imza 0x2f.
Bit akışının ilk 28 biti resmin genişliğini ve yüksekliğini belirtir. Genişlik ve yükseklik, 14 bitlik tam sayılar olarak şu şekilde kodlanır:
int image_width = ReadBits(14) + 1;
int image_height = ReadBits(14) + 1;
Resim genişliği ve yüksekliğinin 14 bit hassasiyeti, bir resmin maksimum 16384 arttırma 16384 piksele kadar WebP kayıpsız resim.
alpha_is_used biti yalnızca bir ipucudur ve kod çözmeyi etkilememelidir. Uygulama resimde tüm alfa değerleri 255 olduğunda 0 olarak, aksi halde 1 olarak ayarlanması gerekir.
int alpha_is_used = ReadBits(1);
version_number, 0 olarak ayarlanması gereken 3 bitlik bir koddur. Diğer tüm değerler hata olarak kabul edilmelidir.
int version_number = ReadBits(3);
4 Dönüşüm
Dönüşümler, görüntü verilerinin ters çevrilebilir şekilde değiştirilmesidir. uzamsal ve renk korelasyonlarını modelleyerek kalan sembolik entropiyi gösterir. Bunlar, son sıkıştırmayı daha yoğun hale getirebilir.
Bir görüntü dört türde dönüşüme tabi tutulabilir. 1 bit, dönüşüm varlığıdır. Her dönüşümün yalnızca bir kez kullanılmasına izin verilir. İlgili içeriği oluşturmak için kullanılan Dönüşümler yalnızca ana düzey ARGB görüntüsü için kullanılır; alt çözünürlüklü resimleri (renk dönüştürme resmi, entropi resmi ve tahminci görüntüsü) dönüşüm içermez, dönüşümlerin sonunu belirten 0 bit bile yoktur.
Kodlayıcı, genellikle Shannon entropisini azaltmak için bu dönüşümleri kullanır. resim olarak ekleyin. Ayrıca, dönüşüm verilerine entropiye göre de karar verilebilir. inceleyebilirsiniz.
while (ReadBits(1)) { // Transform present.
// Decode transform type.
enum TransformType transform_type = ReadBits(2);
// Decode transform data.
...
}
// Decode actual image data (Section 5).
Dönüşüm varsa sonraki iki bit, dönüşüm türünü belirtir. Dört tür dönüşüm vardır.
enum TransformType {
PREDICTOR_TRANSFORM = 0,
COLOR_TRANSFORM = 1,
SUBTRACT_GREEN_TRANSFORM = 2,
COLOR_INDEXING_TRANSFORM = 3,
};
Dönüşüm türünün ardından dönüşüm verileri gelir. Dönüşüm verileri şunları içerir: ters dönüşümü uygulamak için gereken bilgi ve dönüşüm türü. Ters dönüşümler şu sırayla uygulanır: bunlar bit akışından, yani önce sonuncudan okunur.
Daha sonra farklı türler için dönüşüm verilerini açıklayacağız.
4.1 Tahminci Dönüşümü
Tahminci dönüşümü, olgudan yararlanarak entropiyi azaltmak için kullanılabilir. bu da komşu piksellerin genellikle ilişkili olduğunu gösterir. Tahminci dönüşümünde geçerli piksel değeri, kodu çözülmüş piksellerden tahmin edilir (tarama satırında sipariş) ve yalnızca artık değer (gerçek - tahmin edilen) kodlanır. Yeşil bileşeninin 14 göstergeden hangisinin kullanıldığını tanımlar. içeren bir resim öğesi seçin. Tahmin modu, bir tahmindir. Resmi karelere böleriz ve bir bölümdeki tüm pikselleri aynı tahmin modunu kullanır.
Tahmin verilerinin ilk 3 biti, blok genişliği ve yüksekliğini sayı olarak tanımlar. biter.
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);
Dönüşüm verileri, görüntünün her bloğunun tahmin modunu içerir. Google
bir pikselin yeşil bileşeninin hangi pikselin
içindeki tüm block_width * block_height
pikseller için 14 tahminci kullanılır
ARGB resminin belirli bir bloğunu kullanın. Bu alt çözünürlüklü resim, 5. Bölüm'de açıklanan tekniklerle kodlanır.
Blok sütunlarının sayısı (transform_width
) iki boyutlu olarak kullanılır
dizine ekleyin. Bir piksel (x, y) için ilgili filtre bloğu hesaplanabilir
adresini gönderen:
int block_index = (y >> size_bits) * transform_width +
(x >> size_bits);
14 farklı tahmin modu vardır. Her tahmin modunda, piksel değeri, değerleri aynı olan bir veya daha fazla komşu pikselden tahmin edilir zaten biliniyor.
Geçerli pikselin (P) komşu piksellerini (TL, T, TR ve L) şöyle olur:
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
Burada TL sol üst, T üst ve TR sağ üst ve L sol anlamına gelir. Kuyruklu a işareti tüm O, TL, T, TR ve L pikselleri için bir değer tahmin etme zamanı ve P pikseli ile tüm X pikselleri bilinmiyor.
Önceki komşu piksellere göre farklı tahmin modları tanımlanabilir.
Mod | Geçerli pikselin her kanalının tahmini değeri |
---|---|
0 | 0xff000000 (ARGB'de düz siyah rengi temsil eder) |
1 | L |
2 | S |
3 | TR |
4 | ekip lideri |
5 | Ortalama2(Ortalama2(L, TR), T) |
6 | Ortalama2(L, TL) |
7 | Ortalama2(L; T) |
8 | Ortalama2(TL; T) |
9 | Ortalama2(T, TR) |
10 | Ortalama2(Ortalama2(L; TL), Ortalama2(T, TR)) |
11 | Seç(L, T; TL) |
12 | ClampAddSubtractFull(L, T, TL) |
13 | ClampAddSubtractHalf(Average2(L, T), TL) |
Average2
, her bir ARGB bileşeni için aşağıdaki gibi tanımlanır:
uint8 Average2(uint8 a, uint8 b) {
return (a + b) / 2;
}
Tahmin aracı seç aşağıdaki şekilde tanımlanır:
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;
}
}
ClampAddSubtractFull
ve ClampAddSubtractHalf
işlevleri gerçekleştirilir
aşağıdaki gibi her ARGB bileşeni için:
// 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);
}
Bazı kenarlık pikselleri için özel işleme kuralları vardır. Bir tahminci dönüşümü, bu piksellerin modundan [0..13] bağımsız olarak resmin en soldaki pikseli için tahmini değer 0xff000000'dir. en üst satırdaki pikseller L pikseldir ve en soldaki sütundaki tüm pikseller T-piksel.
En sağdaki sütundaki pikseller için TR-pikseli olağanüstü. En sağdaki sütundaki pikseller, modlar kullanılarak tahmin edilir. [0..13], tıpkı kenarlıkta değil, banner'da en soldaki piksel gibi aynı satır bunun yerine TR-piksel olarak kullanılır.
Nihai piksel değeri, tahmin edilen değerden her bir kanal eklenerek elde edilir kodlanan artık değere eşit değildir.
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 Renk Dönüştürme
Renk dönüştürme işleminin amacı, her pikselin R, G ve B değerlerinin korelasyonunu kaldırmaktır. Renk dönüşümü, yeşil (G) değerini olduğu gibi korur, yeşil değeri temel alan kırmızı (R) değerini ve mavi (B) değerini üzerine gelin.
Tahminci dönüşümünde olduğu gibi, önce görüntü, ve bir bloktaki tüm pikseller için aynı dönüştürme modu kullanılır. Örneğin, üç tür renk dönüştürme öğesi vardır.
typedef struct {
uint8 green_to_red;
uint8 green_to_blue;
uint8 red_to_blue;
} ColorTransformElement;
Gerçek renk dönüşümü, bir renk dönüşüm deltası tanımlanarak yapılır. İlgili içeriği oluşturmak için kullanılan
renk dönüşümü delta değeri, aynı olan ColorTransformElement
değerine bağlıdır
her piksel için ayrı bir değerdir. Delta, renk dönüştürme işlemi sırasında çıkarılır. Ters renk dönüştürme işlemi, bu deltaları eklemekten ibarettir.
Renk dönüştürme işlevi aşağıdaki gibi tanımlanır:
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
, değeri temsil eden 8 bitlik imzalı bir tam sayı kullanılarak
3,5 sabit noktalı sayı ve imzalı 8 bit RGB renk kanalı (c) [-128..127]
ve şu şekilde tanımlanır:
int8 ColorTransformDelta(int8 t, int8 c) {
return (t * c) >> 5;
}
ColorTransformDelta()
çağrılmadan önce 8 bitlik işaretsiz temsilden (uint8) 8 bitlik işaretli temsile (int8) dönüştürme işlemi gerekir. İmzalanmış değer
8 bitlik bir ikinin tamamlayıcı sayısı (yani uint8 aralığı) olarak yorumlanmalıdır
[128..255], dönüştürülmüş int8 değerinin [-128..-1] aralığıyla eşlenir).
Çarpma işlemi daha fazla hassasiyet kullanılarak (en az 16 bit hassasiyeti). Kaydırma işleminin işaret uzantısı özelliği önemli değildir burayı tıklayın; sonuçtan yalnızca en düşük 8 bit kullanılır ve bu bitlerde, ve işaretsiz geçişlerin birbirleriyle tutarlı olduğunu gösterir.
Şimdi de kod çözmenin uygulanabilmesi için renk dönüştürme verilerinin içeriğini açıklıyoruz. orijinal kırmızı ve mavi değerlerini kurtarabilirsiniz. İlgili içeriği oluşturmak için kullanılan renk dönüştürme verilerinin ilk 3 biti, renk tonunun genişliğini ve yüksekliğini tahminci dönüşümünde olduğu gibi bit sayısı olan resim bloğu:
int size_bits = ReadBits(3) + 2;
int block_width = 1 << size_bits;
int block_height = 1 << size_bits;
Renk dönüştürme verilerinin geri kalan kısmı, resmin her bloğuna karşılık gelen ColorTransformElement
örneklerini içerir. Her biri
ColorTransformElement
'cte'
, alt çözünürlüklü bir resimde piksel olarak değerlendirilir
alfa bileşeni 255
, kırmızı bileşen cte.red_to_blue
, yeşil
bileşen cte.green_to_blue
, mavi bileşen cte.green_to_red
.
Kod çözme sırasında, ColorTransformElement
blok örneğinin kodu çözülür ve
ters renk dönüşümü, piksellerin ARGB değerlerine uygulanır. Daha önce de belirtildiği gibi, ters renk dönüştürme işlemi yalnızca kırmızı ve mavi kanallara ColorTransformElement
değerleri ekler. Alfa ve yeşil kanallar olduğu gibi bırakılır.
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 Yeşil Çıkarma Dönüşümü
Yeşil çıkarma dönüşümü, yeşil değerleri şu öğenin kırmızı ve mavi değerlerinden çıkarır: her bir pikselde bir araya gelir. Bu dönüşüm mevcut olduğunda kod çözücünün yeşil renk eklemesi hem kırmızı hem de mavi değerlere ayarlayın. Bununla ilişkilendirilmiş veri yok gerekir. Kod çözücü, ters dönüşümü şu şekilde uygular:
void AddGreenToBlueAndRed(uint8 green, uint8 *red, uint8 *blue) {
*red = (*red + green) & 0xff;
*blue = (*blue + green) & 0xff;
}
Bu dönüşüm, renk dönüşümü kullanılarak modellenebileceği için gereksizdir ancak burada ek veri olmadığından, yeşil çıkarma dönüşümü daha az bit kullanarak kodlanır.
4.4 Renk Dizine Ekleme Dönüşümü
Çok sayıda benzersiz piksel değeri yoksa, tek bir sistem kullanarak renk dizini dizisi oluşturur ve piksel değerlerini dizinin dizinleriyle değiştirir. Renk dizine ekleme dönüşümü bunu sağlar. (WebP kayıpsız bağlamında özellikle benzer ancak daha farklı dinamik kavram WebP kayıpsız kodlamada bulunur: renk önbelleği.)
Renk dizine ekleme dönüşümü, resimdeki benzersiz ARGB değerlerinin sayısını kontrol eder. Bu sayı bir eşiğin (256) altındaysa bu değerlerin bir dizisi oluşturur ARGB değerleri (daha sonra piksel değerlerini karşılık gelen dizin: piksellerin yeşil kanalı dizini için, tüm alfa değerleri 255 ve tüm kırmızı ve mavi değerleri 0 olarak ayarlanır.
Dönüşüm verileri, renk tablosu boyutunu ve renkteki girişleri içerir tablosunu oluşturalım. Kod çözücü, renk dizine ekleme dönüşüm verilerini şu şekilde okur:
// 8-bit value for the color table size
int color_table_size = ReadBits(8) + 1;
Renk tablosu, resim depolama biçiminin kendisi kullanılarak depolanır. Renk tablosu
RIFF başlığı, resim boyutu ve bağlantısı olmadan bir resim okunarak elde edilebilir.
1 piksel yüksekliğinde ve color_table_size
genişliğinde olduğu varsayılarak dönüştürülür.
Renk tablosu, görüntü entropisini azaltmak için her zaman çıkarma kodludur. Deltalar
palet renklerinin entropileri genellikle renklerden çok daha azdır
Bu da daha küçük resimlerde önemli tasarruf sağlar. Kod çözme işleminde, önceki renk bileşeni değerleri her ARGB bileşenine ayrı ayrı eklenip sonucun en az anlamlı 8 biti depolanarak renk tablosundaki her nihai renk elde edilebilir.
Resim için ters dönüşüm, basitçe piksel değerlerinin (bu, renk tablosu dizinleridir). Dizine ekleme ARGB renginin yeşil bileşeni temel alınarak yapılır.
// Inverse transform
argb = color_table[GREEN(argb)];
Dizin color_table_size
değerine eşit veya bu değerden büyükse argb renk değeri 0x00000000 (şeffaf siyah) olarak ayarlanmalıdır.
Renk tablosu küçükse (16 renge eşit veya daha az renge eşitse) birkaç piksel tek bir piksel halinde gruplandırılır. Piksel gruplandırması birkaç (2, 4 veya 8) paketi içerir pikselleri tek piksele dönüştürür ve sırasıyla resim genişliğini azaltır. Piksel paketleme, verilerin daha verimli bir şekilde ortak dağıtım entropi kodlamasına komşu pikseller oluşturur ve entropi kodu içerir, ancak yalnızca 16 veya daha az benzersiz değer olduğunda kullanılabilir.
color_table_size
, kaç pikselin birleştirildiğini belirtir:
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
öğesinin değeri 0, 1, 2 veya 3'tür. 0 değeri, piksel olmadığını gösterir
gruplama yapılır. 1 değeri, iki pikselin
ve her pikselin [0..15] aralığı vardır. 2 değeri, dört pikselin birleştirildiğini ve her pikselin [0..3] aralığına sahip olduğunu gösterir. 3 değeri
sekiz pikselin birleştirildiğini ve her pikselin [0..1],
yani ikilik değerdir.
Değerler, yeşil bileşene şu şekilde yerleştirilir:
width_bits
= 1: Her x değeri için x Re 0 (mod 2), bir yeşil değeri, x'teki değer, rastgele sayı x / 2'deki yeşil bir değer ve x + 1'deki yeşil bir değer x / 2'deki yeşil değerin 4 en önemli biti.width_bits
= 2: Her x değeri için, x SYMBOL 0 (mod 4), bir yeşil x'teki değer, x / 4'teki yeşil değer ve x + 1 - x + 3 aralığındaki yeşil değerler x / 4'teki yeşil değerin daha önemli bitlerine göre sıralanır.width_bits
= 3: Her x değeri için x kazançları 0 (mod 8), yeşil x'teki değer, yeşilin en az anlamlı bitine konumlandırılır x / 8'deki değer ve x + 1 - x + 7 arasındaki yeşil değerler sırayla konumlandırılır x / 8'deki yeşil değerin daha önemli bitlerine ekler.
Bu dönüşüm okunduktan sonra image_width
, width_bits
tarafından alt örneklenir. Bu
sonraki dönüşümlerin boyutunu etkiler. Yeni boyut şöyle hesaplanabilir:
Daha önce tanımlandığı şekliyle DIV_ROUND_UP
.
image_width = DIV_ROUND_UP(image_width, 1 << width_bits);
5 Resim Verileri
Resim verileri, tarama satırı sırasına göre bir piksel değeri dizisidir.
5.1 Resim Verilerinin Rolleri
Resim verilerini beş farklı rolde kullanırız:
- ARGB resmi: Resmin gerçek piksellerini depolar.
- Entropi resmi: Meta ön ek kodlarını depolar ("Meta Ön Ek Kodlarının Kod Çözülmesi" bölümüne bakın).
- Tahmin aracı resmi: Tahmin aracı dönüşümünün meta verilerini depolar ("Tahmin aracı dönüşümü" bölümüne bakın).
- Renk dönüştürme resmi:
ColorTransformElement
değerleri tarafından oluşturuldu ("Renk Dönüşümü" bölümünde tanımlanmıştır) için farklı bloklar gösterir. - Renk dizine ekleme resmi: Renk dizine ekleme dönüştürme işleminin meta verilerini depolayan
color_table_size
boyutunda (256'a kadar ARGB değeri) bir dizi ("Renk dizine ekleme dönüştürme" bölümüne bakın).
5.2 Resim Verilerinin Kodlanması
Resim verilerinin kodlanması rolünden bağımsızdır.
Resim önce bir dizi sabit boyutlu bloka bölünür (genellikle 16x16 boyutundaki). blok) seçebilirsiniz. Bu blokların her biri kendi entropi kodları kullanılarak modellenir. Ayrıca, birkaç blok aynı entropi kodlarını paylaşabilir.
Mantık: Entropy kodu depolamak maliyetlidir. Maliyet en aza indirebilir İstatistiksel olarak benzer bloklar bir entropi kodunu paylaşır ve böylece bu kodu yalnızca bir kez. Örneğin, kodlayıcı benzer blokları kümeleyerek bulabilir. kullanarak veya rastgele sayılarla bir çifti sürekli olarak birleştirerek kodlamak için gereken toplam bit miktarını azalttığında, seçtiğiniz kümeler resim.
Her piksel, aşağıdaki üç olası yöntemden biri kullanılarak kodlanır:
- Ön ek kodlu değişmez değerler: Her kanal (yeşil, kırmızı, mavi ve alfa) bağımsız olarak entropi kodlanmıştır.
- LZ77 geriye dönük referansı: Bir piksel dizisi, resim.
- Renk önbelleği kodu: Kısa bir çarpımsal karma kodu (renk önbelleği) dizini) görürsünüz.
Aşağıdaki alt bölümlerde bunların her biri ayrıntılı olarak açıklanmaktadır.
5.2.1 Ön Ek Kodlu Değişmez Değerler
Piksel, ön ek kodlu yeşil, kırmızı, mavi ve alfa değerleri olarak depolanır sipariş). Aşağıdaki özellikler için bkz. Bölüm 6.2.3 bolca fırsat sunuyor.
5.2.2 LZ77 Geriye Dönük Referansı
Geriye dönük referanslar, uzunluk ve mesafe kodu demetleridir:
- Uzunluk, tarama satırı sırasına göre kaç pikselin kopyalanacağını belirtir.
- Mesafe kodu, daha önce görülen bir yerin konumunu gösteren bir sayıdır piksellerin kopyalanacağı piksel. Tam eşleme aşağıda açıklanmıştır.
Uzunluk ve mesafe değerleri LZ77 önek kodlaması kullanılarak depolanır.
LZ77 ön ek kodlaması, büyük tam sayı değerlerini iki bölüme ayırır: önek kodu ve ekstra bit değerlerini ekleyin. Önek kodu, bir entropi kodu kullanılarak depolanır ekstra bitler oldukları gibi (entropi kodu olmadan) depolanır.
Mantıksal: Bu yaklaşım entropi için depolama gereksinimini azaltır girin. Ayrıca, büyük değerler genellikle nadiren görülür. Bu nedenle, değer ekleyemeyeceğim. Böylece, bu yaklaşım sayesinde yardımcı olabilir.
Aşağıdaki tabloda, izin verebilirsiniz.
Değer aralığı | Önek kodu | Ekstra bitler |
---|---|---|
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 |
Önek kodundan bir (uzunluk ya da mesafe) değeri elde etmek için sözde kod şöyle olabilir: şöyle olur:
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;
Mesafe Eşleme
Daha önce belirtildiği gibi, mesafe kodu bir nesnenin konumunu gösteren bir sayıdır daha önce görülen ve piksellerin kopyalanacağı piksel. Bu alt bölüm mesafe kodu ile önceki bir uzaklık kodu arasındaki konum piksel.
120'den büyük mesafe kodları, piksel mesafesini tarama çizgisine göre belirtir. farkı 120'ye çıkarır.
En küçük mesafe kodları [1..120] özeldir ve yakın zamandaki ne kadarının nerede olduğunu gösterir. Bu mahalle 120 pikselden oluşur:
- Mevcut pikselin 1 ila 7 satır üstü ve 8 sütun sola veya 7 sütun sağa olan pikseller. [Toplam
bu tür piksellerin sayısı =
7 * (8 + 1 + 7) = 112
]. - Geçerli pikselle aynı satırda bulunan ve en fazla 8 adet olan pikseller
sütunlarını tıklayın. [
8
bu tür piksel].
distance_code
mesafe kodu ile komşu piksel arasındaki eşleme
(xi, yi)
ofseti aşağıdaki gibidir:
(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)
Örneğin, mesafe kodu 1
, komşu piksel için (0, 1)
ofset'ini (mevcut pikselin üzerindeki piksel) gösterir (X yönünde 0 piksel ve Y yönünde 1 piksel fark).
Benzer şekilde, mesafe kodu 3
sol üstteki pikseli belirtir.
Kod çözücü, distance_code
mesafe kodunu tarama çizgisi sırasına dönüştürebilir
dist
mesafesi şu şekildedir:
(xi, yi) = distance_map[distance_code - 1]
dist = xi + yi * image_width
if (dist < 1) {
dist = 1
}
Burada distance_map
yukarıda belirtilen eşleme, image_width
ise genişliktir
piksel cinsinden kaydedin.
5.2.3 Renk Önbelleği Kodlaması
Renk önbelleği, resimde son zamanlarda kullanılan bir dizi rengi depolar.
Mantıksal: Bu şekilde, son kullanılan renkler bazen diğer iki yöntemi kullanarak yayınlamaktan daha etkilidir (bkz. 5.2.1 ve 5.2.2) dâhildir.
Renk önbellek kodları aşağıdaki gibi depolanır. İlk olarak, renk önbelleğinin kullanılıp kullanılmadığını gösterir. Bu bit 0 ise, renk önbellek kodu bulunmaz ve bunlar, yeşil renk kodunu çözen önek kodunda iletilmez ve uzunluk öneki kodları kullanabilirsiniz. Ancak bu bit 1 ise sırada renk önbelleği boyutu okunur:
int color_cache_code_bits = ReadBits(4);
int color_cache_size = 1 << color_cache_code_bits;
color_cache_code_bits
, renk önbelleğinin (1 <<
color_cache_code_bits
) boyutunu tanımlar. Şunun için izin verilen değer aralığı:
color_cache_code_bits
[1..11] tarihinde. Uyumlu kod çözücüler
diğer değerler için bozuk bit akışı.
Renk önbelleği, color_cache_size
boyutunda bir dizidir. Her giriş bir ARGB depolar
rengi. Renkler (0x1e35a7bd * color) >> (32 -
color_cache_code_bits)
tarafından dizine eklenerek aranır. Renk önbelleğinde yalnızca bir arama yapılır; yok
çatışmaların çözümü.
Bir resmin kodunu çözmenin veya kodlamanın başında, tüm renkli tüm girişler önbellek değerleri sıfır olarak ayarlanır. Renk önbelleği kodu, kod çözme sırasında bu renge dönüştürülür. Renk önbelleği, geriye dönük referansla veya değişmez değerler olarak üretilen her pikseli akışta göründükleri sırayla önbelleğe ekleyerek korunur.
6 Entropi Kodu
6.1 Genel bakış
Verilerin çoğu standart ön ek kodu kullanılarak kodlanır. Bu nedenle, kodlar gerçek ön ek kodlarının yerine ön ek kod uzunlukları gönderilerek iletilir.
Özellikle bu biçim, uzamsal varyant ön ek kodlamasını kullanır. Başka resmin farklı blokları potansiyel olarak farklı entropi kullanabilir ekleyebilirsiniz.
Açıklama: Resmin farklı alanlarının farklı özellikleri olabilir. Dolayısıyla, farklı entropi kodları kullanmalarına izin vermek daha fazla esneklik sağlar ve daha iyi sıkıştırma olasılığı vardır.
6.2 Ayrıntılar
Kodlanmış resim verileri birkaç bölümden oluşur:
- Ön ek kodlarının kodunu çözme ve oluşturma.
- Meta ön ek kodları.
- Entropi kodlu görüntü verileri.
Belirli bir piksel (x, y) için, şununla ilişkili beş ön ek kodundan oluşan bir küme vardır: somut olarak ortaya koyar. Bu kodlar (bit akışı sırasına göre):
- Ön ek kodu #1: Yeşil kanal, geriye dönük referans uzunluğu ve renk önbelleği için kullanılır.
- Önek kodu 2, #3 ve #4: Kırmızı, mavi ve alfa kanalları için kullanılır. tıklayın.
- Ön ek kodu #5: Geriye dönük referans mesafesi için kullanılır.
Bundan böyle, bu küme bir önek kod grubu olarak adlandırılır.
6.2.1 Önek Kodlarının Kodunu Çözme ve Oluşturma
Bu bölümde, ön ek kodu uzunluklarının bit akışından nasıl okunacağı açıklanmaktadır.
Önek kodu uzunlukları iki şekilde kodlanabilir. Kullanılan yöntem belirtilmiş bir veri kümesi oluşturun.
- Bu bit 1 ise basit bir kod uzunluğu kodudur.
- Bu bit 0 ise normal kod uzunluğu kodudur.
Her iki durumda da, hâlâ deneme süresinin bir parçası olan kullanılmayan kod uzunlukları akış şeklinde gösterilir. Bu verimsiz olabilir ancak biçim nedeniyle izin verilir. Açıklanan ağaç tam bir ikili ağaç olmalıdır. Tek yapraklı düğüm tam bir ikili ağacı kabul edilir ve veya normal kod uzunluğu kodu olabilir. Tek bir yaprağı kodlarken normal kod uzunluğu kodunu kullanan bir düğüm varsa biri hariç tümünün uzunluğu sıfırdır. Tek yapraklı düğüm değerinin uzunluğu ise 1 olarak işaretlenir ( bitlerinin tüketildiğini gösterir.
Basit Kod Uzunluğu Kodu
Bu varyant, kod uzunluğu 1
olan [0..255] aralığında yalnızca 1 veya 2 ön ek sembolünün bulunduğu özel durumda kullanılır. Diğer tüm ön ek kodu uzunlukları
sıfıra eşittir.
İlk bit, simgelerin sayısını belirtir:
int num_symbols = ReadBits(1) + 1;
Sembol değerleri aşağıda verilmiştir.
Bu ilk sembol, 1 veya 8 bit kullanılarak kodlanmıştır.
is_first_8bits
Aralık, sırasıyla [0..1] veya [0..255] şeklindedir. Varsa ikinci sembolün her zaman [0..255] aralığında olduğu ve 8 bit kullanılarak kodlandığı varsayılır.
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;
}
Bu iki simge farklı olmalıdır. Yinelenen simgelere izin verilir verimsizdir.
Not: Diğer bir özel durum da tüm önek kodu uzunluklarının sıfır (sıfır) olmasıdır.
önek kodu ekleyin). Örneğin, mesafe için bir önek kodu aşağıdaki durumlarda boş olabilir:
geriye dönük referans yoktur. Benzer şekilde, alfa, kırmızı ve
aynı meta önek kodu içinde tüm pikseller üretilirse mavi boş olabilir
kullanmanızı öneririz. Ancak bu durumun özel olarak ele alınması gerekmez çünkü
boş önek kodları, tek sembollü 0
simgesi içeren kodlar şeklinde kodlanabilir.
Normal Kod Uzunluğu Kodu
Önek kodunun kod uzunlukları 8 bite sığar ve aşağıdaki gibi okunur.
İlk olarak, num_code_lengths
, kod uzunluklarının sayısını belirtir.
int num_code_lengths = 4 + ReadBits(4);
Kod uzunlukları ise ön ek kodları kullanılarak kodlanır; alt düzey kod
uzunluklar, code_length_code_lengths
, önce okunması gerekiyor. Bu code_length_code_lengths
değerlerinin geri kalanı (kCodeLengthCodeOrder
'daki sıraya göre) sıfırdır.
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);
}
Sonra, ReadBits(1) == 0
ise maksimum farklı okuma sembolü sayısı
(max_symbol
) her simge türü (A, R, G, B ve mesafe) için
alfabe boyutu:
- G kanalı: 256 + 24 +
color_cache_size
- Diğer değişmez değerler (A, R ve B): 256
- Mesafe kodu: 40
Aksi takdirde şu şekilde tanımlanır:
int length_nbits = 2 + 2 * ReadBits(3);
int max_symbol = 2 + ReadBits(length_nbits);
max_symbol
, sembol türü için alfabenin boyutundan büyükse
bit akışı geçersiz.
Daha sonra code_length_code_lengths
öğesinden bir önek tablosu oluşturulur ve
en çok max_symbol
kod uzunluğunda olabilir.
- Kod [0..15], değişmez kod uzunluklarını belirtir.
- 0 değeri, hiçbir sembolün kodlanmadığı anlamına gelir.
- [1..15] değerleri, ilgili kodun bit uzunluğunu belirtir.
- 16 numaralı kod, önceki sıfır olmayan değeri [3..6] kez, yani
3 + ReadBits(2)
kez tekrar eder. Kod 16, sıfır olmayan bir değerden önce kullanılırsa değer gönderildiyse 8 değeri tekrarlanır. - Kod 17, sıfır uzunluğunda [3..10], yani
3 + ReadBits(3)
kez bir seri yayar. - Kod 18, sıfır uzunluğunda bir seri yayar [11..138], yani
11 + ReadBits(7)
defa.
Kod uzunlukları okunduktan sonra, her sembol türü (A, R, G, B ve mesafe), ilgili alfabe boyutları kullanılarak oluşturulur.
Normal Kod Uzunluğu Kodu tam bir karar ağacını, yani
Sıfır olmayan tüm kodlar için 2 ^ (-length)
tam olarak bir olmalıdır. Bununla birlikte,
bu kuralın bir istisnası vardır: Yaprak düğümünün bulunduğu tek yapraklı düğüm ağacı
değer 1, diğer değerler ise 0s olarak işaretlenir.
6.2.2 Meta Önek Kodlarının Kodunu Çözme
Daha önce de belirtildiği gibi bu biçim, bloklarından oluşur. Meta ön ek kodları, hangi dizinlerin resmin farklı bölümlerinde kullanılacak ön ek kodları.
Meta ön ek kodları yalnızca resim bir ARGB resmi rolünde kullanıldığında kullanılabilir.
Meta ön ek kodları için, 1 bit ile belirtilen iki olasılık vardır. değer:
- Bu bit sıfırsa her yerde yalnızca bir meta ön ek kodu kullanılır resim. Daha fazla veri depolanmaz.
- Bu bit bir bitse resimde birden çok meta önek kodu kullanılır. Bu meta önek kodları bir entropi resmi (aşağıda açıklanmıştır) olarak saklanır.
Bir pikselin kırmızı ve yeşil bileşenleri ARGB resminin belirli bir bloğunu kullanın.
Entropi Resmi
Entropi resmi, anahtar kelimenin farklı kısımlarında hangi ön ek kodların kullanıldığını görüntüsüdür.
İlk 3 bit, prefix_bits
değerini içerir. Entropinin boyutları
görüntü, prefix_bits
kaynağından türetilir:
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);
Bu örnekte DIV_ROUND_UP
, daha önce tanımlandığı gibidir.
Sonraki bitler, genişliği prefix_image_width
ve yüksekliği olan bir entropi resmi içerir
prefix_image_height
.
Meta Önek Kodlarının Yorumlanması
ARGB resmindeki ön ek kodu gruplarının sayısı, entropi resmindeki en büyük meta ön ek kodu:
int num_prefix_groups = max(entropy image) + 1;
Burada max(entropy image)
,
entropi resmidir.
Her ön ek kodu grubu beş ön ek kodu içerdiğinden, öneklerin toplam sayısı kodlar:
int num_prefix_codes = 5 * num_prefix_groups;
ARGB resmindeki bir piksel (x, y) göz önüne alındığında, kodlardan birini seçin:
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];
Burada, beş ön ek kodundan oluşan bir kümeyi temsil eden PrefixCodeGroup
yapısının varlığını varsaydık. Ayrıca, prefix_code_groups
,
PrefixCodeGroup
(num_prefix_groups
boyutunda).
Ardından kod çözücü, pikselin kodunu çözmek için prefix_group
ön ek kod grubunu kullanır
(x, y), "Entropi Kodlu Resmin Kodunu Çözme" bölümünde açıklandığı gibi
Veri".
6.2.3 Entropi Kodlu Resim Verilerinin Kodunu Çözme
Resimdeki geçerli konum (x, y) için kod çözücü ilk olarak karşılık gelen önek kodu grubuna dokunun (son bölümde açıklandığı şekilde). Raporda önek kod grubunda, piksel aşağıdaki gibi okunur ve kodu çözülür.
Ardından, ön ek kodu 1'i kullanarak bit akışından S simgesini okuyun. S'nin 0
ile (256 + 24 +
color_cache_size
- 1)
aralığındaki herhangi bir tam sayı olduğunu unutmayın.
S'nin yorumlanması değerine bağlıdır:
- S < 256 ise
- Yeşil bileşen olarak S kullanın.
- 2 numaralı ön ek kodunu kullanarak bit akışından kırmızıyı okuyun.
- Ön ek kodu 3'ü kullanarak bit akışından maviyi okuyun.
- Ön ek kodu 4'ü kullanarak bit akışından alfayı okuyun.
- S >= 256 ve S < 256 + 24
- Uzunluk ön eki kodu olarak S - 256 değerini kullanın.
- Bit akışından gelen uzunluk için ekstra bitleri okuyun.
- Uzunluk ön ek kodu ve okunan ekstra bitlerden geri referans uzunluğu L'yi belirleyin.
- 5 numaralı ön ek kodunu kullanarak bit akışından mesafe ön ek kodunu okuyun.
- Bit akışından uzaklık için ekstra bitleri okuyun.
- Mesafe ön ek kodu ve okunan ek bitlerden geriye referans mesafesi D'yi belirleyin.
- L piksellerini (tarama satırı sırasına göre) başlayan piksel dizisinden kopyala eksi D piksel olarak görünür.
- S >= 256 + 24 ise
- Renk önbelleğine dizin olarak S - (256 + 24) değerini kullanın.
- Bu dizindeki renk önbelleğinden ARGB rengi alın.
7 Biçimin Genel Yapısı
Aşağıda, Artırılmış Backus-Naur Formu (ABNF) biçiminde bir görünüm verilmiştir RFC 5234 RFC 7405. Tüm ayrıntıları kapsamaz. Resmin sonu (EOI) yalnızca örtülü olarak piksel sayısı (image_width * image_height) olarak kodlanır.
*element
değerinin, element
değerinin 0 veya daha fazla kez tekrarlanabileceği anlamına geldiğini unutmayın. 5element
element
değerinin tam olarak 5 kez tekrarlandığı anlamına gelir. %b
, ikilik bir değeri temsil eder.
7.1 Temel Yapı
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 Dönüşümlerin Yapısı
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 Resim Verilerinin Yapısı
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)
Aşağıda olası bir dizi örnek verilmiştir:
RIFF-header image-size %b1 subtract-green-tx
%b1 predictor-tx %b0 color-cache-info
%b0 prefix-codes lz77-coded-image