Jyrki Alakuijala, Ph.D., Google, Inc., 2023-03-09
Soyut
WebP kayıpsız, ARGB resimlerin kayıpsız sıkıştırılması için kullanılan bir resim biçimidir. Kayıpsız biçim, tamamen şeffaf piksellerin renk değerleri de dahil olmak üzere piksel değerlerini tam olarak saklar ve geri yükler. Toplu verilerin sıkıştırılması için sıralı veri sıkıştırma (LZ77), önek kodlama ve renk önbelleği için evrensel bir algoritma kullanılır. PNG'den daha hızlı kod çözme hızlarının yanı sıra günümüzün PNG biçimiyle elde edilebilecek sıkıştırmadan% 25 daha yoğun sıkıştırma gösterilmiştir.
1 Giriş
Bu belgede, WebP kayıpsız görüntüsünün sıkıştırılmış veri gösterimi açıklanmaktadır. WebP kayıpsız kodlayıcı ve kod çözücü uygulaması için ayrıntılı bir referans olarak hazırlanmıştır.
Bu belgede, bit akışını açıklamak için C programlama dili söz dizimi yoğun bir şekilde kullanılmakta ve bitleri okumak için bir işlevin (ReadBits(n)) varlığı varsayılmaktadır. Baytlar, bunları içeren akışın doğal sırasına göre okunur ve her baytın bitleri, en az anlamlı bit önce olacak şekilde okunur. Aynı anda birden fazla bit okunduğunda tam sayı, orijinal sıradaki orijinal verilerden oluşturulur. Döndürülen tam sayının en önemli bitleri, orijinal verilerin de en önemli bitleridir. Bu nedenle,
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 gibi her renk bileşeninin 8 bitlik bir bayt kullanılarak temsil edildiğini varsayıyoruz. Karşılık gelen türü uint8 olarak tanımlarız. ARGB pikselin tamamı, 32 bitlik işaretsiz bir tam sayı olan uint32 adlı bir türle temsil edilir. Dönüşümlerin davranışını gösteren kodda bu değerler aşağıdaki bitlerde kodlanmıştır: 31-24 bitlerde alfa, 23-16 bitlerde kırmızı, 15-8 bitlerde yeşil ve 7-0 bitlerde mavi. Ancak biçimin uygulamaları, dahili olarak başka bir gösterim kullanabilir.
Genel olarak, WebP kayıpsız görüntüsü başlık verileri, dönüştürme bilgileri ve gerçek görüntü verilerini içerir. Başlıklar, resmin genişliğini ve yüksekliğini içerir. Kayıpsız bir WebP resmi, entropi kodlaması yapılmadan önce dört farklı dönüştürme işleminden geçebilir. Bit akışındaki dönüştürme bilgileri, ilgili ters dönüştürmelerin uygulanması için gereken verileri içerir.
2 Adlandırma
- ARGB
- Alfa, kırmızı, yeşil ve mavi değerlerinden oluşan bir piksel değeri.
- ARGB resmi
- ARGB piksellerini içeren iki boyutlu bir dizi.
- renk önbelleği
- Kısa kodlarla hatırlanabilmesi için son kullanılan renkleri depolayan küçük bir karma adresli dizi.
- renk dizine ekleme görüntüsü
- Küçük bir tam sayı (WebP kayıpsız biçiminde 256'ya kadar) kullanılarak dizine eklenebilen, tek boyutlu bir renk görüntüsü.
- renk dönüştürme görüntüsü
- Renk bileşenlerinin korelasyonları hakkında veriler içeren iki boyutlu bir alt çözünürlüklü görüntü.
- mesafe eşleme
- LZ77 mesafelerini, iki boyutlu yakınlıktaki pikseller için en küçük değerlere sahip olacak şekilde değiştirir.
- entropi görüntüsü
- Resimde hangi entropi kodlamasının kullanılması gerektiğini belirten iki boyutlu bir alt çözünürlük görüntüsü. Yani her piksel bir meta önek kodudur.
- LZ77
- Sözlüğe dayalı bir kayan pencere sıkıştırma algoritmasıdır. Semboller yayar veya bunları geçmiş sembollerin dizileri olarak tanımlar.
- meta önek kodu
- Meta önek tablosundaki bir öğeyi dizine ekleyen küçük bir tam sayı (16 bit'e kadar).
- tahmin resmi
- Görüntüdeki belirli bir kare için hangi mekansal tahmincinin kullanıldığını gösteren iki boyutlu bir alt çözünürlük görüntüsü.
- önek kodu
- Daha sık kullanılan kodlar için daha az sayıda bitin kullanıldığı klasik bir entropi kodlama yöntemidir.
- ön ek kodlaması
- Daha büyük tam sayıları entropi kodlamanın bir yolu. Bu yöntem, tam sayının birkaç bitini entropi kodu kullanarak kodlar ve kalan bitleri ham olarak kodlar. Bu sayede, sembol aralığı büyük olsa bile entropi kodlarının açıklamaları nispeten küçük kalır.
- tarama çizgisi sırası
- Piksellerin, sol üstteki pikselden başlayarak soldan sağa ve yukarıdan aşağıya doğru işlenme sırası. Bir satır tamamlandığında sonraki satırın sol sütunundan devam edin.
3 RIFF Header
Başlığın başında RIFF kapsayıcısı bulunur. Bu, aşağıdaki 21 bayttan oluşur:
- "RIFF" dizesi.
- RIFF üstbilgisi tarafından kontrol edilen parçanın tüm boyutu olan parça uzunluğunun little-endian, 32 bitlik değeri. Normalde bu, yük boyutuna (dosya boyutu eksi 8 bayt: "RIFF" tanımlayıcısı için 4 bayt ve değerin kendisini depolamak için 4 bayt) eşittir.
- "WEBP" dizesi (RIFF kapsayıcı adı).
- "VP8L" dizesi (kayıpsız kodlanmış resim verileri için FourCC).
- Kayıpsız akıştaki bayt sayısının little-endian, 32 bitlik değeri.
- 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 aşağıdaki şekilde kod çözülür:
int image_width = ReadBits(14) + 1;
int image_height = ReadBits(14) + 1;
Resim genişliği ve yüksekliği için 14 bitlik hassasiyet, WebP kayıpsız resimlerin maksimum boyutunu 16384✕16384 piksel ile sınırlar.
alpha_is_used biti yalnızca bir ipucudur ve kod çözme işlemini etkilememelidir. Resimdeki tüm alfa değerleri 255 olduğunda 0, aksi takdirde 1 olarak ayarlanmalıdır.
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 geri döndürülebilir şekilde değiştirilmesidir. Bu değişiklikler, mekansal ve renk korelasyonlarını modelleyerek kalan sembolik entropiyi azaltabilir. Son sıkıştırmayı daha yoğun hale getirebilirler.
Bir resim dört tür dönüşümden geçebilir. 1 bit, dönüştürmenin varlığını gösterir. Her dönüşüm yalnızca bir kez kullanılabilir. Dönüşümler yalnızca ana düzeydeki ARGB görüntüsü için kullanılır. Alt çözünürlüklü görüntülerde (renk dönüştürme görüntüsü, entropi görüntüsü ve tahmin görüntüsü) dönüşüm yoktur. Dönüşümlerin sonunu belirten 0 bit'i bile yoktur.
Genellikle bir kodlayıcı, artık görüntüdeki Shannon entropisini azaltmak için bu dönüşümleri kullanır. Ayrıca, veri dönüşümüne entropi minimizasyonuna göre karar verilebilir.
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üştürme vardır.
enum TransformType {
PREDICTOR_TRANSFORM = 0,
COLOR_TRANSFORM = 1,
SUBTRACT_GREEN_TRANSFORM = 2,
COLOR_INDEXING_TRANSFORM = 3,
};
Dönüşüm türünü, dönüşüm verileri izler. Verileri dönüştürme, ters dönüşümü uygulamak için gereken bilgileri içerir ve dönüşüm türüne bağlıdır. Ters dönüşümler, bit akışından okundukları sıranın tersine uygulanır. Yani önce sonuncusu uygulanır.
Ardından, farklı türlerdeki verileri dönüştürme işlemi açıklanmaktadır.
4.1 Tahmin Edici Dönüşümü
Tahminci dönüşümü, komşu piksellerin genellikle ilişkili olduğu gerçeğinden yararlanarak entropiyi azaltmak için kullanılabilir. Tahmin edici dönüşümünde, mevcut piksel değeri önceden çözülmüş piksellerden (tarama çizgisi sırasına göre) tahmin edilir ve yalnızca artık değer (gerçek - tahmin edilen) kodlanır. Bir pikselin yeşil bileşeni, ARGB görüntüsünün belirli bir bloğunda 14 tahmin ediciden hangisinin kullanılacağını tanımlar. Tahmin modu, kullanılacak tahmin türünü belirler. Resmi karelere böleriz ve bir karedeki tüm pikseller aynı tahmin modunu kullanır.
Tahmin verilerinin ilk 3 biti, blok genişliğini ve yüksekliğini bit sayısı olarak tanımlar.
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üştürme verileri, görüntünün her bloğu için tahmin modunu içerir. Bu, bir pikselin yeşil bileşeninin, ARGB resminin belirli bir bloğundaki tüm block_width * block_height pikseller için 14 tahmin ediciden hangisinin kullanılacağını tanımladığı bir alt çözünürlüklü resimdir. Bu alt çözünürlüklü görüntü, 5. Bölüm'de açıklanan teknikler kullanılarak kodlanır.
Blok sütun sayısı (transform_width), iki boyutlu dizin oluşturmada kullanılır. Bir piksel (x, y) için ilgili filtre bloğu adresi şu şekilde hesaplanabilir:
int block_index = (y >> size_bits) * transform_width +
(x >> size_bits);
14 farklı tahmin modu vardır. Her tahmin modunda, geçerli piksel değeri, değerleri zaten bilinen bir veya daha fazla komşu pikselden tahmin edilir.
Mevcut pikselin (P) komşu piksellerini (TL, T, TR ve L) aşağıdaki gibi seçtik:
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; TR, sağ üst; L ise sol anlamına gelir. P pikseli için değer tahmin edilirken tüm O, TL, T, TR ve L pikselleri işlenmiş, P pikseli ve tüm X pikselleri ise bilinmemektedir.
Önceki komşu pikseller göz önüne alındığında, farklı tahmin modları aşağıdaki gibi tanımlanır.
| Mod | Mevcut pikselin her kanalının tahmini değeri |
|---|---|
| 0 | 0xff000000 (ARGB'de düz siyah rengi temsil eder) |
| 1 | L |
| 2 | T |
| 3 | TR |
| 4 | TL |
| 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 | Select(L, T, TL) |
| 12 | ClampAddSubtractFull(L, T, TL) |
| 13 | ClampAddSubtractHalf(Average2(L, T), TL) |
Average2, her ARGB bileşeni için aşağıdaki şekilde tanımlanır:
uint8 Average2(uint8 a, uint8 b) {
return (a + b) / 2;
}
Tahminci seçme özelliği 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, her ARGB bileşeni için aşağıdaki gibi gerçekleştirilir:
// 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 tahmin dönüştürme işlemi varsa bu piksellerin modu [0..13] ne olursa olsun, resmin sol üstteki pikselinin tahmin edilen değeri 0xff000000'dır, üst satırdaki tüm pikseller L pikseldir ve en soldaki sütundaki tüm pikseller T pikseldir.
En sağdaki sütundaki pikseller için TR pikselinin ele alınması istisnadır. En sağdaki sütundaki pikseller, kenarlıkta olmayan pikseller gibi modlar[0..13] kullanılarak tahmin edilir. Ancak geçerli pikselle aynı satırdaki en soldaki piksel bunun yerine TR-piksel olarak kullanılır.
Son piksel değeri, tahmin edilen değerin her kanalının kodlanmış artık değere eklenmesiyle elde edilir.
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üşümü
Renk dönüşümünün amacı, her pikselin R, G ve B değerlerini bağımsızlaştırmaktır. Renk dönüşümü, yeşil (G) değerini olduğu gibi korur, kırmızı (R) değerini yeşil değere göre dönüştürür ve mavi (B) değerini önce yeşil değere, ardından kırmızı değere göre dönüştürür.
Tahminci dönüşümünde olduğu gibi, önce görüntü bloklara bölünür ve bir bloktaki tüm pikseller için aynı dönüşüm modu kullanılır. Her blok iç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ü, renk dönüşümü deltası tanımlanarak yapılır. Renk dönüşümü deltası, belirli bir bloktaki tüm pikseller için aynı olan ColorTransformElement değerine bağlıdır. Renk dönüşümü sırasında delta çıkarılır. Ters renk dönüşümü, bu farkları eklemekten ibarettir.
Renk dönüştürme işlevi şu şekilde 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, 3,5 sabit noktalı sayıyı temsil eden imzalı 8 bitlik bir tam sayı ve imzalı 8 bitlik bir RGB renk kanalı (c) [-128..127] kullanılarak hesaplanır ve şu şekilde tanımlanır:
int8 ColorTransformDelta(int8 t, int8 c) {
return (t * c) >> 5;
}
ColorTransformDelta() çağrılmadan önce 8 bit işaretsiz gösterimden (uint8) 8 bit işaretli gösterime (int8) dönüştürme yapılması gerekir. İşaretli değer, 8 bitlik ikinin tümleyeni sayısı olarak yorumlanmalıdır (yani: uint8 aralığı [128..255], dönüştürülmüş int8 değerinin [-128..-1] aralığına eşlenir).
Çarpma işlemi daha hassas bir şekilde (en az 16 bit hassasiyetle) yapılmalıdır. Kaydırma işleminin işaret genişletme özelliği burada önemli değildir. Sonuçtan yalnızca en düşük 8 bit kullanılır ve bu bitlerde işaret genişletme kaydırma ile işaretsiz kaydırma birbirleriyle tutarlıdır.
Şimdi, renk dönüştürme verilerinin içeriğini açıklıyoruz. Böylece kod çözme işlemi, ters renk dönüştürmeyi uygulayabilir ve orijinal kırmızı ve mavi değerleri kurtarabilir. Renk dönüştürme verilerinin ilk 3 biti, tahmin dönüştürmede olduğu gibi görüntü bloğunun genişliğini ve yüksekliğini bit sayısı olarak içerir:
int size_bits = ReadBits(3) + 2;
int block_width = 1 << size_bits;
int block_height = 1 << size_bits;
Renk dönüşümü verilerinin geri kalan kısmı, resmin her bir bloğuna karşılık gelen ColorTransformElement örneklerini içerir. Her ColorTransformElement 'cte', alfa bileşeni 255, kırmızı bileşeni cte.red_to_blue, yeşil bileşeni cte.green_to_blue ve mavi bileşeni cte.green_to_red olan bir alt çözünürlüklü görüntüdeki piksel olarak değerlendirilir.
Kod çözme sırasında, blokların ColorTransformElement örneklerinin kodu çözülür ve piksellerin ARGB değerlerine ters renk dönüşümü uygulanır. Daha önce belirtildiği gibi, ters renk dönüşümü 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şili çıkarma dönüşümü, her pikselin kırmızı ve mavi değerlerinden yeşil değerleri çıkarır. Bu dönüştürme işlemi mevcut olduğunda kod çözücünün yeşil değeri hem kırmızı hem de mavi değerlere eklemesi gerekir. Bu dönüşümle ilişkilendirilmiş veri yok. Kod çözücü, ters dönüşümü aşağıdaki şekilde uygular:
void AddGreenToBlueAndRed(uint8 green, uint8 *red, uint8 *blue) {
*red = (*red + green) & 0xff;
*blue = (*blue + green) & 0xff;
}
Bu dönüştürme, renk dönüştürmesi kullanılarak modellenebildiği için gereksizdir. Ancak burada ek veri olmadığından yeşili çıkarma dönüştürmesi, tam teşekküllü bir renk dönüştürmesinden daha az bit kullanılarak kodlanabilir.
4.4 Renk Dizine Ekleme Dönüşümü
Çok fazla benzersiz piksel değeri yoksa bir renk dizini dizisi oluşturmak ve piksel değerlerini dizinin dizinleriyle değiştirmek daha verimli olabilir. Bu işlem, renk dizini oluşturma dönüşümüyle gerçekleştirilir. (WebP kayıpsız bağlamında, benzer ancak daha dinamik bir kavram WebP kayıpsız kodlamada (renk önbelleği) mevcut olduğundan bu işleme özellikle palet dönüşümü adını vermiyoruz.)
Renk dizini oluşturma dönüşümü, resimdeki benzersiz ARGB değerlerinin sayısını kontrol eder. Bu sayı bir eşiğin (256) altındaysa bu ARGB değerlerinden oluşan bir dizi oluşturulur. Bu dizi daha sonra piksel değerlerini karşılık gelen dizinle değiştirmek için kullanılır: Piksellerin yeşil kanalı dizinle değiştirilir, tüm alfa değerleri 255'e, tüm kırmızı ve mavi değerleri ise 0'a ayarlanır.
Dönüştürülen veriler, renk tablosu boyutunu ve renk tablosundaki girişleri içerir. Kod çözücü, renk dizine ekleme dönüştürme verilerini aşağıdaki gibi okur:
// 8-bit value for the color table size
int color_table_size = ReadBits(8) + 1;
Renk tablosu, görüntü depolama biçimi kullanılarak depolanır. Renk tablosu, RIFF başlığı, resim boyutu ve dönüşümler olmadan bir resim okunarak elde edilebilir. Bu işlemde, yüksekliğin 1 piksel ve genişliğin color_table_size olduğu varsayılır.
Renk tablosu, görüntü entropisini azaltmak için her zaman çıkarma kodludur. Palet renklerinin deltaları genellikle renklerin kendisinden çok daha az entropi içerir. Bu da daha küçük resimlerde önemli ölçüde tasarruf sağlar. Kod çözme işleminde, renk tablosundaki her son renk, önceki renk bileşeni değerleri her ARGB bileşeni için ayrı ayrı eklenerek ve sonucun en az anlamlı 8 biti saklanarak elde edilebilir.
Görüntünün ters dönüşümü, piksel değerlerinin (renk tablosunun dizinleri) gerçek renk tablosu değerleriyle değiştirilmesinden ibarettir. Dizin oluşturma işlemi, ARGB renginin yeşil bileşenine göre 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üçük olduğunda (16 renge eşit veya daha az) birkaç piksel tek bir pikselde birleştirilir. Piksel paketleme, birkaç (2, 4 veya 8) pikseli tek bir pikselde birleştirerek görüntü genişliğini buna göre azaltır. Piksel paketleme, komşu piksellerin daha verimli ortak dağıtım entropi kodlamasına olanak tanır ve entropi koduna aritmetik kodlamaya benzer bazı avantajlar sağlar ancak yalnızca 16 veya daha az benzersiz değer olduğunda kullanılabilir.
color_table_size kaç pikselin birleştirileceğ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 değeri 0, 1, 2 veya 3 olmalıdır. 0 değeri, resim için piksel gruplandırması yapılmayacağını gösterir. 1 değeri, iki pikselin birleştirildiğini ve her pikselin [0..15] aralığında olduğunu gösterir. 2 değeri, dört pikselin birleştirildiğini ve her pikselin [0..3] aralığında olduğunu gösterir. 3 değeri, sekiz pikselin birleştirildiğini ve her pikselin [0..1] aralığında olduğunu (yani ikili değer) gösterir.
Değerler, yeşil bileşene aşağıdaki şekilde yerleştirilir:
width_bits= 1: x ≡ 0 (mod 2) olan her x değeri için x'teki yeşil değer, x / 2'deki yeşil değerin en az önemli 4 bitine, x + 1'deki yeşil değer ise x / 2'deki yeşil değerin en önemli 4 bitine yerleştirilir.width_bits= 2: x ≡ 0 (mod 4) olan her x değeri için x'teki yeşil değer, x / 4'teki yeşil değerin en az anlamlı 2 bitine yerleştirilir ve x + 1 ile x + 3 arasındaki yeşil değerler, x / 4'teki yeşil değerin daha anlamlı bitlerine sırayla yerleştirilir.width_bits= 3: x ≡ 0 (mod 8) olan her x değeri için x'teki yeşil değer, x / 8'deki yeşil değerin en az anlamlı bitine yerleştirilir ve x + 1 ile x + 7 arasındaki yeşil değerler, x / 8'deki yeşil değerin daha anlamlı bitlerine sırayla yerleştirilir.
Bu dönüşüm okunduktan sonra image_width, width_bits ile alt örneklenir. Bu, sonraki dönüştürmelerin boyutunu etkiler. Yeni boyut, daha önce tanımlandığı gibi DIV_ROUND_UP kullanılarak hesaplanabilir.
image_width = DIV_ROUND_UP(image_width, 1 << width_bits);
5. Görüntü Verileri
Resim verileri, tarama çizgisi sırasındaki piksel değerleri dizisidir.
5.1 Görüntü Verilerinin Rolleri
Görüntü verilerini beş farklı rolde kullanırız:
- ARGB resmi: Resmin gerçek piksellerini depolar.
- Entropi resmi: Meta önek kodlarını depolar (bkz. "Meta Önek Kodlarının Kodunu Çözme").
- Tahmin edici resmi: Tahmin edici dönüşümünün meta verilerini depolar (bkz. "Tahmin Edici Dönüşümü").
- Renk dönüştürme resmi: Resmin farklı blokları için
ColorTransformElementdeğerleri ("Renk Dönüştürme" bölümünde tanımlanır) kullanılarak oluşturulur. - Renk dizinleme görüntüsü: Renk dizinleme dönüşümüyle ilgili meta verileri depolayan,
color_table_sizeboyutunda bir dizi (256 ARGB değerine kadar) (bkz. "Renk Dizinleme Dönüşümü").
5.2 Görüntü Verilerinin Kodlanması
Resim verilerinin kodlaması, rolünden bağımsızdır.
Resim önce sabit boyutlu bir dizi bloğa (genellikle 16x16 blok) bölünür. Bu blokların her biri kendi entropi kodları kullanılarak modellenir. Ayrıca, birkaç blok aynı entropi kodlarını paylaşabilir.
Gerekçe: Bir entropi kodunu depolamak maliyetlidir. İstatistiksel olarak benzer bloklar bir entropi kodu paylaştığında bu maliyet en aza indirilebilir. Bu durumda, kod yalnızca bir kez depolanır. Örneğin, bir kodlayıcı, benzer blokları istatistiksel özelliklerini kullanarak kümeleyebilir veya görüntüyü kodlamak için gereken toplam bit miktarını azalttığında rastgele seçilmiş bir küme çiftini tekrar tekrar birleştirerek bulabilir.
Her piksel, üç olası yöntemden biri kullanılarak kodlanır:
- Önek kodlu sabit değerler: Her kanal (yeşil, kırmızı, mavi ve alfa) bağımsız olarak entropi kodludur.
- LZ77 geriye doğru referans: Bir piksel dizisi, resmin başka bir yerinden kopyalanır.
- Renk önbelleği kodu: Yakın zamanda görülen bir rengin kısa çarpımsal karma kodu (renk önbelleği dizini) kullanılır.
Aşağıdaki alt bölümlerde bunların her biri ayrıntılı olarak açıklanmıştır.
5.2.1 Önek Kodlu Değişmez Değerler
Piksel, yeşil, kırmızı, mavi ve alfa değerleri (bu sırayla) olarak saklanır. Ayrıntılar için 6.2.3 Bölümü'ne bakın.
5.2.2 LZ77 Geriye Dönük Referans
Geriye dönük referanslar, uzunluk ve mesafe kodu demetleridir:
- Uzunluk, tarama çizgisi sırasındaki kaç pikselin kopyalanacağını gösterir.
- Uzaklık kodu, daha önce görülen ve piksellerin kopyalanacağı pikselin konumunu gösteren bir sayıdır. Tam eşleme aşağıda açıklanmıştır.
Uzunluk ve mesafe değerleri, LZ77 önek kodlaması kullanılarak depolanır.
LZ77 önek kodlaması, büyük tam sayı değerlerini iki parçaya böler: önek kodu ve ekstra bitler. Önek kodu, bir entropi kodu kullanılarak saklanır. Ek bitler ise olduğu gibi (entropi kodu olmadan) saklanır.
Gerekçe: Bu yaklaşım, entropi kodu için depolama alanı gereksinimini azaltır. Ayrıca, büyük değerler genellikle nadir olduğundan, resimdeki çok az değer için ek bitler kullanılır. Bu nedenle, bu yaklaşım genel olarak daha iyi sıkıştırma sağlar.
Aşağıdaki tabloda, farklı değer aralıklarını depolamak için kullanılan önek kodları ve ek bitler gösterilmektedir.
| 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 (uzunluk veya mesafe) değeri elde etmeye yönelik sözde kod aşağıdaki gibidir:
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 Haritalama
Daha önce belirtildiği gibi, uzaklık kodu, daha önce görülen bir pikselin konumunu gösteren ve piksellerin kopyalanacağı bir sayıdır. Bu alt bölümde, mesafe kodu ile önceki pikselin konumu arasındaki eşleme tanımlanmaktadır.
120'den büyük uzaklık kodları, tarama çizgisi sırasındaki piksel uzaklığını 120 ile dengelenmiş olarak gösterir.
En küçük mesafe kodları [1..120] özeldir ve mevcut pikselin yakın çevresi için ayrılmıştır. Bu mahalle 120 pikselden oluşuyor:
- Mevcut pikselin 1 ila 7 satır üstünde ve mevcut pikselin en fazla 8 sütun solunda veya en fazla 7 sütun sağında olan pikseller. [Toplam
bu tür pikseller =
7 * (8 + 1 + 7) = 112]. - Geçerli pikselle aynı satırda bulunan ve geçerli pikselin en fazla 8 sütun solunda yer alan pikseller. [
8piksel].
Uzaklık kodu distance_code ile komşu piksel
kayması (xi, yi) arasındaki eşleme 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, 1 uzaklık kodu, komşu piksel için (0, 1) uzaklık olduğunu gösterir. Bu, geçerli pikselin üzerindeki pikseldir (X yönünde 0 piksel fark ve Y yönünde 1 piksel fark).
Benzer şekilde, uzaklık kodu 3 sol üstteki pikseli gösterir.
Kod çözücü, bir mesafe kodunu distance_code tarama çizgisi sırası mesafesine dist aşağıdaki gibi dönüştürebilir:
(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 resmin piksel cinsinden genişliğidir.
5.2.3 Renk Önbelleği Kodlaması
Renk önbelleği, resimde yakın zamanda kullanılan bir dizi rengi depolar.
Gerekçe: Bu şekilde, son kullanılan renklere bazen diğer iki yöntem (5.2.1 ve 5.2.2 bölümlerinde açıklanmıştır) kullanılarak renk yaymaktan daha verimli bir şekilde başvurulabilir.
Renk önbelleği kodları aşağıdaki şekilde saklanır. İlk olarak, renk önbelleğinin kullanılıp kullanılmadığını belirten 1 bitlik bir değer vardır. Bu bit 0 ise renk önbelleği kodları yoktur ve yeşil sembollerin ve uzunluk önek kodlarının kodunu çözen önek kodunda iletilmez. Ancak bu bit 1 ise 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 boyutunu (1 <<
color_cache_code_bits) tanımlar. color_cache_code_bits için izin verilen değer aralığı [1..11]'dir. Uygun kod çözücüler, diğer değerler için bozuk bir bit akışı olduğunu belirtmelidir.
Renk önbelleği, color_cache_size boyutunda bir dizidir. Her giriş bir ARGB rengi depolar. Renkler, (0x1e35a7bd * color) >> (32 -
color_cache_code_bits) ile dizine eklenerek aranır. Renk önbelleğinde yalnızca bir arama yapılır; çakışma çözümü yoktur.
Bir görüntünün kodunun çözülmesinin veya kodlanmasının başında, tüm renk önbelleği değerlerindeki tüm girişler sıfıra ayarlanır. Renk önbelleği kodu, kod çözme sırasında bu renge dönüştürülür. Renk önbelleğinin durumu, her pikselin (geriye doğru referanslama veya değişmez değerler kullanılarak üretilmiş olsa bile) akışta göründükleri sırayla önbelleğe eklenmesiyle 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ı yerine ön ek kod uzunlukları gönderilerek iletilir.
Özellikle bu biçimde konuma göre değişen önek kodlaması kullanılır. Başka bir deyişle, resmin farklı blokları farklı entropi kodları kullanabilir.
Gerekçe: Resmin farklı alanları farklı özelliklere sahip olabilir. Bu nedenle, farklı entropi kodları kullanmalarına izin vermek daha fazla esneklik ve muhtemelen daha iyi sıkıştırma sağlar.
6.2 Ayrıntılar
Kodlanmış resim verileri çeşitli bölümlerden oluşur:
- Ön ek kodlarını çözme ve oluşturma.
- Meta önek kodları.
- Entropi kodlu görüntü verileri.
Belirli bir piksel (x, y) için bununla ilişkili beş önek kodu vardır. Bu kodlar (bit akışı sırasına göre):
- Önek kodu #1: Yeşil kanal, geriye doğru referans uzunluğu ve renk önbelleği için kullanılır.
- Önek kodu #2, #3 ve #4: Sırasıyla kırmızı, mavi ve alfa kanalları için kullanılır.
- Ön ek kodu #5: Geriye dönük referans mesafesi için kullanılır.
Bu küme, bundan sonra önek kodu grubu olarak adlandırılacaktır.
6.2.1 Önek Kodlarının Kodunu Çözme ve Oluşturma
Bu bölümde, bit akışından önek kodu uzunluklarının nasıl okunacağı açıklanmaktadır.
Önek kodu uzunlukları iki şekilde kodlanabilir. Kullanılan yöntem, 1 bitlik bir değerle belirtilir.
- Bu bit 1 ise basit kod uzunluğu kodu'dur.
- Bu bit 0 ise normal kod uzunluğu kodu olur.
Her iki durumda da akışın bir parçası olan, kullanılmamış kod uzunlukları olabilir. Bu yöntem verimli olmayabilir ancak biçim tarafından izin verilir. Açıklanan ağaç, tam ikili ağaç olmalıdır. Tek bir yaprak düğüm, tam ikili ağaç olarak kabul edilir ve basit kod uzunluğu kodu veya normal kod uzunluğu kodu kullanılarak kodlanabilir. Normal kod uzunluğu kodu kullanılarak tek bir yaprak düğümü kodlanırken bir kod uzunluğu hariç tüm kod uzunlukları sıfırdır ve tek yaprak düğümü değeri, bu tek yaprak düğümü ağacı kullanıldığında bit tüketilmemiş olsa bile 1 uzunluğuyla işaretlenir.
Basit Kod Uzunluğu Kodu
Bu varyant, yalnızca 1 veya 2 önek sembolünün 1 kod uzunluğuyla [0..255] aralığında olduğu özel durumda kullanılır. Diğer tüm önek kodu uzunlukları dolaylı olarak sıfırdır.
İlk bit, sembol sayısını gösterir:
int num_symbols = ReadBits(1) + 1;
Sembol değerleri aşağıda verilmiştir.
Bu ilk sembol, is_first_8bits değerine bağlı olarak 1 veya 8 bit kullanılarak kodlanır. Aralık sırasıyla [0..1] veya [0..255]'tir. 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;
}
İki sembol farklı olmalıdır. Yinelenen sembollere izin verilir ancak bu durum verimsizdir.
Not: Bir diğer özel durum ise tüm önek kodu uzunluklarının sıfır olmasıdır (boş bir önek kodu). Örneğin, geriye doğru referans yoksa mesafe için önek kodu boş olabilir. Benzer şekilde, aynı meta ön ek kodu içindeki tüm pikseller renk önbelleği kullanılarak üretiliyorsa alfa, kırmızı ve mavi için ön ek kodları boş olabilir. Ancak bu durumda özel işlem yapılması gerekmez. Çünkü boş ön ek kodları, tek bir sembol 0 içeren kodlar olarak kodlanabilir.
Normal Kod Uzunluğu Kodu
Önek kodunun kod uzunlukları 8 bit'e 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ı, önek kodları kullanılarak kodlanır. Daha düşük düzeydeki kod uzunlukları, code_length_code_lengths, önce okunmalıdır. code_length_code_lengths geri kalanı (kCodeLengthCodeOrder içindeki 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);
}
Ardından, ReadBits(1) == 0 ise her sembol türü (A, R, G, B ve mesafe) için farklı okuma sembollerinin maksimum sayısı (max_symbol) alfabe boyutuna ayarlanır:
- 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 değeri, sembol türü için alfabenin boyutundan büyükse bit akışı geçersizdir.
Daha sonra code_length_code_lengths öğesinden bir önek tablosu oluşturulur ve max_symbol kod uzunluklarına kadar okumak için kullanılır.
- Kod [0..15], değişmez kod uzunluklarını belirtir.
- 0 değeri, sembol kodlanmadığı anlamına gelir.
- [1..15] değerleri, ilgili kodun bit uzunluğunu gösterir.
- 16 kodu, önceki sıfır olmayan değeri [3..6] kez, yani
3 + ReadBits(2)kez tekrar eder. Sıfır olmayan bir değer yayınlanmadan önce 16 kodu kullanılırsa 8 değeri tekrarlanır. - 17 kodu, [3..10] uzunluğunda bir sıfır dizisi (yani
3 + ReadBits(3)kez) yayar. - 18 kodu, [11..138] uzunluğunda bir sıfır dizisi, yani
11 + ReadBits(7)kez yayar.
Kod uzunlukları okunduktan sonra, her simge türü (A, R, G, B ve mesafe) için kendi alfabe boyutları kullanılarak bir önek kodu oluşturulur.
Normal Kod Uzunluğu Kodu, tam bir karar ağacını kodlamalıdır. Yani, sıfır olmayan tüm kodlar için 2 ^ (-length) toplamı tam olarak bir olmalıdır. Ancak bu kuralın tek bir istisnası vardır: tek yapraklı düğüm ağacı. Bu ağaçta yapraklı düğüm değeri 1 ile işaretlenir ve diğer değerler 0 olur.
6.2.2 Meta Önek Kodlarının Kodunu Çözme
Daha önce de belirtildiği gibi, bu biçim, resmin farklı blokları için farklı önek kodlarının kullanılmasına olanak tanır. Meta önek kodları, resmin farklı bölümlerinde hangi önek kodlarının kullanılacağını belirleyen indekslerdir.
Meta önek kodları yalnızca resim, rol olarak ARGB resmi şeklinde kullanıldığında kullanılabilir.
Meta önek kodları için 1 bitlik bir değerle belirtilen iki olasılık vardır:
- Bu bit sıfırsa resimde her yerde yalnızca bir meta önek kodu kullanılır. Başka veri depolanmaz.
- Bu bit bir ise resimde birden fazla meta önek kodu kullanılıyor demektir. Bu meta önek kodları, entropi resmi olarak saklanır (aşağıda açıklanmıştır).
Bir pikselin kırmızı ve yeşil bileşenleri, ARGB görüntüsünün belirli bir bloğunda kullanılan 16 bitlik bir meta önek kodu tanımlar.
Entropi Resmi
Entropi resmi, resmin farklı bölümlerinde hangi önek kodlarının kullanıldığını tanımlar.
İlk 3 bit, prefix_bits değerini içerir. Entropi resminin boyutları prefix_bits öğesinden 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);
Burada DIV_ROUND_UP, daha önce tanımlandığı gibidir.
Sonraki bitler, genişliği prefix_image_width ve yüksekliği prefix_image_height olan bir entropi resmi içerir.
Meta Önek Kodlarının Yorumlanması
ARGB resmindeki önek kodu gruplarının sayısı, entropi resminden en büyük meta önek kodu bulunarak elde edilebilir:
int num_prefix_groups = max(entropy image) + 1;
Burada max(entropy image), entropi resminde depolanan en büyük önek kodunu gösterir.
Her önek kodu grubu beş önek kodu içerdiğinden toplam önek kodu sayısı şöyledir:
int num_prefix_codes = 5 * num_prefix_groups;
ARGB resmindeki bir piksel (x, y) verildiğinde, aşağıdaki gibi kullanılacak ilgili önek kodlarını elde edebiliriz:
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];
PrefixCodeGroup yapısının varlığını varsaydığımız yerlerde. Bu yapı, beş önek kodundan oluşan bir grubu temsil eder. Ayrıca, prefix_code_groups, PrefixCodeGroup dizisidir (boyutu num_prefix_groups).
Daha sonra kod çözücü, "Kodlanmış Görüntü Verilerinin Kodunu Çözme" bölümünde açıklandığı gibi, pikselin (x, y) kodunu çözmek için önek kodu grubu prefix_group'yı kullanır.
6.2.3 Entropi Kodlu Görüntü Verilerinin Kodunu Çözme
Resimdeki mevcut konum (x, y) için kod çözücü önce ilgili önek kodu grubunu (son bölümde açıklandığı gibi) tanımlar. Önek kodu grubu göz önüne alındığında, piksel aşağıdaki gibi okunur ve kodu çözülür.
Ardından, 1 numaralı önek kodunu kullanarak bit akışından S sembolünü okuyun. S'nin, 0 ile (256 + 24 + color_cache_size- 1) aralığında 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'yi kullanın.
- Ön ek kodu #2'yi kullanarak bit akışından kırmızı rengi okuyun.
- Ön ek kodu #3'ü kullanarak bit akışından mavi rengi okuyun.
- Ön ek kodu #4'ü kullanarak bit akışından alfa değerini okuyun.
- S >= 256 & S < 256 + 24 ise
- Uzunluk önek kodu olarak S - 256'yı kullanın.
- Bit akışından uzunluk için ekstra bitler okuyun.
- Geriye doğru referans uzunluğu L'yi, uzunluk önek kodundan ve okunan ek bitlerden belirleyin.
- Ön ek kodu #5'i kullanarak bit akışından mesafe ön ek kodunu okuyun.
- Bit akışından uzaklık için ekstra bitleri okur.
- Mesafe önek kodu ve okunan ek bitlerden geriye doğru referans mesafesi D'yi belirleyin.
- Geçerli konumdan D piksel çıkarılarak elde edilen konumdan başlayarak piksel dizisinden L pikseli (tarama çizgisi sırasına göre) kopyalar.
- S >= 256 + 24 ise
- Renk önbelleğinde dizin olarak S - (256 + 24) değerini kullanın.
- Bu dizindeki renk önbelleğinden ARGB rengini alır.
7 Biçimin Genel Yapısı
Aşağıda, Artırılmış Backus-Naur Formu (ABNF) RFC 5234 RFC 7405 biçimindeki bir görünüm yer almaktadır. Tüm ayrıntıları kapsamaz. Resim sonu (EOI), yalnızca piksel sayısına (image_width * image_height) örtülü olarak kodlanır.
*element ifadesinin, element ifadesinin 0 veya daha fazla kez tekrarlanabileceği anlamına geldiğini unutmayın. 5element
element öğesinin tam olarak 5 kez tekrarlandığı anlamına gelir. %b, ikili 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 Görüntü 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 örnek sıra verilmiştir:
RIFF-header image-size %b1 subtract-green-tx
%b1 predictor-tx %b0 color-cache-info
%b0 prefix-codes lz77-coded-image