WebP Kayıpsız Bit Akışı spesifikasyonu

Jyrki Alakuijala, Ph.D., Google, Inc., 2023-03-09

Özet

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 dahil olmak üzere piksel değerlerini tam olarak depolar ve geri yükler. Toplu verilerin sıkıştırılması için sıralı veri sıkıştırma (LZ77) için evrensel bir algoritma (LZ77), ön ek kodlaması ve bir renk önbelleği kullanılır. PNG'den daha hızlı kod çözme ve günümüzün PNG biçimini kullanarak mümkün olandan% 25 daha yoğun bir sıkıştırma değeri gösterilmiştir.

1 Giriş

Bu belgede, bir WebP kayıpsız görüntüsünün sıkıştırılmış veri temsili açıklanmaktadı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, bit akışını tanımlamak için C programlama dili söz dizimini yoğun bir şekilde kullanıyoruz ve bitleri okumak için bir işlevin (ReadBits(n)) mevcut olduğunu varsayıyoruz. Baytlar, kendilerini içeren akışın doğal sırasında okunur ve her baytın bitleri, en az anlamlı olan bit öncelikli sırada okunur. Aynı anda birden fazla bit okunduğunda tam sayı, orijinal verilerden orijinal sıradaki sırayla oluşturulur. Döndürülen tam sayının en önemli bitleri, aynı zamanda orijinal verilerin en önemli bitleridir. Böylelikle,

b = ReadBits(2);

aşağıdaki iki ifadeyle eşdeğerdir:

b = ReadBits(1);
b |= ReadBits(1) << 1;

Her bir renk bileşeninin (alfa, kırmızı, mavi ve yeşil) 8 bit bayt kullanılarak temsil edildiğini varsayıyoruz. Karşılık gelen türü uint8 olarak tanımlarız. Tam bir ARGB pikseli, 32 bitten oluşan imzasız bir tam sayı olan uint32 adlı bir türle temsil edilir. Dönüşümlerin davranışını gösteren kodda, bu değerler şu bitlerde kodlanmıştır: 31..24 bitlerinde alfa, 23..16 bitlerinde kırmızı, 15..8 bitlerinde yeşil ve 7..0 bitlerinde mavi. Bununla birlikte, biçimde başka bir gösterim dahili olarak serbest bir şekilde kullanılabilir.

Genel olarak, bir WebP kayıpsız resim başlık verilerini, dönüşüm bilgilerini ve gerçek resim verilerini içerir. Başlıklar, resmin genişliğini ve yüksekliğini içerir. WebP kayıpsız görüntü, entropi kodlanmadan önce dört farklı dönüşüm türünden geçebilir. Bit akışındaki dönüşüm bilgileri, ilgili ters dönüşümleri uygulamak için gereken verileri içerir.

2 Nomenklatür

ARGB
Alfa, kırmızı, yeşil ve mavi değerlerden oluşan bir piksel değeridir.
ARGB resmi
ARGB piksellerini içeren iki boyutlu dizi.
renk önbelleği
Son kullanılan renkleri daha kısa kodlarla geri çağırabilmek amacıyla bu renkleri depolayan küçük bir karma çözümlü dizi.
renkli dizine ekleme resmi
Küçük bir tam sayı kullanılarak dizine eklenebilen tek boyutlu renkler resmi (WebP'de kayıpsız 256'ya kadar).
renk dönüştürme resmi
Renk bileşenlerinin korelasyonları hakkında veriler içeren iki boyutlu alt çözünürlüklü görüntü.
mesafe haritası
LZ77 mesafelerini, iki boyutlu yakınlıktaki pikseller için en küçük değerlere sahip olacak şekilde değiştirir.
entropi resmi
Resimdeki ilgili karede hangi entropi kodlamasının kullanılması gerektiğini gösteren iki boyutlu alt çözünürlüklü resim, yani her piksel bir meta önek kodudur.
LZ77
Sembol oluşturan veya bunları eski sembollerden oluşan bir dizi olarak tanımlayan, sözlük tabanlı bir kayan pencere sıkıştırma algoritması.
meta önek kodu
Meta ön ek tablosundaki bir öğeyi dizine ekleyen küçük bir tam sayı (16 bite kadar).
tahmin aracı görüntüsü
Resimdeki belirli bir kare için hangi konumsal önleyicinin kullanıldığını gösteren iki boyutlu alt çözünürlüklü görüntü.
önek kodu
Daha sık kodlar için daha az sayıda bit kullanıldığı entropi kodlamasının klasik yöntemi.
önek kodlaması
Daha büyük tam sayıları entropi yöntemi olarak kodlayın. Bu yöntem, bir entropi kodu kullanarak tam sayının birkaç bitini kodlayıp kalan bitleri ham olarak kodlar. Bu, sembol aralığı büyük olsa bile entropi kodlarının açıklamalarının nispeten küçük kalmasını sağlar.
tarama satırı sırası
Sol üstteki pikselden başlayarak piksellerin işleme sırası (soldan sağa ve yukarıdan aşağıya). Bir satır tamamlandığında, sonraki satırın sol tarafındaki sütundan devam edin.

3 RIFF Başlığı

Başlığın başında RIFF kapsayıcısı vardır. Aşağıdaki 21 bayttan oluşur:

  1. "RIFF" dizesi.
  2. Yığın uzunluğunun küçük uçlu, 32 bit değeri. Bu değer, RIFF başlığı tarafından kontrol edilen yığının tüm boyutudur. Normalde bu değer, 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).
  3. "WEBP" dizesi (RIFF kapsayıcı adı).
  4. Dize "VP8L" (Kayıpsız kodlanmış resim verileri için FourCC).
  5. Kayıpsız akıştaki bayt sayısının küçük uçlu, 32 bit değeri.
  6. 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üksekliğin kodu 14 bitlik tam sayılar olarak şu şekilde çö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 bit hassasiyet, WebP kayıpsız resmin maksimum boyutunu 16.384416384 pikselle sınırlandırır.

alpha_is_used biti yalnızca bir ipucudur ve kod çözmeyi etkilememelidir. Resimdeki tüm alfa değerleri 255 olduğunda 0 olarak, 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 değerler hata olarak değerlendirilmelidir.

int version_number = ReadBits(3);

4 Dönüşüm

Dönüşümler, resim verileri üzerinde ters çevrilebilir manipülasyonlardır. Bu manipülasyonlar, uzamsal ve renk korelasyonlarını modelleyerek kalan sembolik entropiyi azaltabilir. Son sıkıştırmayı daha yoğun hale getirebilirler.

Bir görüntü dört tür dönüşümden geçebilir. 1 bit ise bir dönüşümün varlığını gösterir. Her dönüşümün yalnızca bir kez kullanılmasına izin verilir. Dönüştürmeler yalnızca ana seviyedeki 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 önleyici görüntüsü), dönüşümlerin sonunu belirten 0 biti bile yoktur.

Tipik olarak, bir kodlayıcı, kalan görüntüdeki Shannon entropisini azaltmak için bu dönüşümleri kullanır. Ayrıca, dönüşüm verilerine entropi küçültme işlemi temel alınarak 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).

Bir 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, 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ıralamanın tersine, yani en sonda olacak şekilde uygulanır.

Ardından, farklı türler için dönüştürme verilerini açıklayacağız.

4.1 Tahmin Aracı Dönüşümü

Tahmin aracı dönüşümü, komşu piksellerin genellikle ilişkili olduğu gerçeğinden yararlanarak entropiyi azaltmak için kullanılabilir. Tahmin aracı dönüşümünde, geçerli piksel değeri, kodu daha önce çözülmüş piksellerden (tarama satırı sırasında) tahmin edilir ve yalnızca artık değer (gerçek - tahmin edilen) kodlanır. Bir pikselin yeşil bileşeni, ARGB resminin belirli bir bloğunda 14 belirleyiciden hangisinin kullanıldığı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, bit sayısı olarak blok genişliğini ve yüksekliğini 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, resmin her bir 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 pikselleri için 14 ön göstergeden hangisinin kullanıldığı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 kodlanmıştır.

İki boyutlu dizine eklemede blok sütunlarının (transform_width) sayısı 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.

Geçerli pikselin (P) komşu piksellerini (TL, T, TR ve L) şu şekilde 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 sağ üst, TR sağ üst ve L sol üst anlamına gelir. P değeri tahmin edilirken tüm O, TL, T, TR ve L pikselleri işlenmiş ve P pikseli ile X piksellerinin tamamı bilinmiyor.

Önceki komşu piksellere göre farklı tahmin modları aşağıdaki gibi tanımlanır.

Mod Geçerli pikselin her bir kanalının tahmini değeri
0 0xff000000 (ARGB'de düz siyah rengi temsil eder)
1 L
2 T
3 (Türk lirası)
4 TL
5 Ortalama2(Ortalama 2(L; TR); T)
6 Ortalama2(L, TL)
7 Ortalama2(D; 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;
}

Seç tahmincisi 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 bir ARGB bileşeni için aşağıdaki şekilde 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üşümü varsa, bu pikseller için modda [0..13] modundan bağımsız olarak, resmin en soldaki pikseli için tahmin edilen değer 0xff000000, üst satırdaki tüm pikseller L-piksel ve en soldaki sütundaki tüm pikseller T pikseldir.

En sağdaki sütunda yer alan pikseller için TR pikselinin ele alınması olağanüstü bir durumdur. En sağdaki sütundaki pikseller, [0..13] modları kullanılarak tahmin edilir. Bu modlar, tıpkı kenarlıkta olmayan pikseller gibidir. Bunun yerine, geçerli pikselle aynı satırda bulunan en soldaki piksel, bunun yerine TR pikseli olarak kullanılır.

Son piksel değeri, tahmin edilen değerin her bir 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üştürme

Renk dönüştürme işleminin amacı, her bir pikselin R, G ve B değerlerini uygun hale getirmektir. 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 yeşil değere ve ardından kırmızı değerine dönüştürür.

Önleyici dönüşümde olduğu gibi, önce görüntü bloklara ayrılır ve bir bloktaki tüm pikseller için aynı dönüştürme 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. Bu durumda ters renk dönüşümü, yalnızca bu deltaları ekliyor.

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ı bir sayıyı ve işaretli 8 bit RGB renk kanalını (c) [-128..127] temsil eden işaretli bir 8 bitlik tam sayı 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 bitlik imzasız gösterimden (uint8) 8 bit imzalı gösterime (int8) dönüştürülmesi gerekir. İşaretli değer, 8 bitlik ikinin tamamlayıcı sayısı olarak yorumlanmalıdır (yani uint8 aralığı [128..255], dönüştürülen int8 değerinin [-128..-1] aralığıyla eşlenir).

Çarpma işlemi, daha fazla hassasiyetle (en az 16 bit kesinlikte) yapılır. Kaydırma işleminin işaret uzantısı özelliği burada önemli değildir; sonuçta yalnızca en düşük 8 bit kullanılır ve burada, işaret uzantısı kaydırma ve imzasız kaydırma birbirleriyle tutarlıdır.

Şimdi, kod çözme işleminin ters renk dönüşümünü uygulayabilmesi ve orijinal kırmızı ve mavi değerlerini kurtarabilmesi için renk dönüştürme verilerinin içeriklerini açıklıyoruz. Renk dönüştürme verilerinin ilk 3 biti, önleyici dönüşümde olduğu gibi, resim 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üştürme verilerinin geri kalan kısmı, resmin her bir bloğuna karşılık gelen ColorTransformElement örnek içerir. Her ColorTransformElement 'cte', alfa bileşeni 255, kırmızı bileşen cte.red_to_blue, yeşil bileşen cte.green_to_blue ve mavi bileşen cte.green_to_red olan alt çözünürlüklü bir resimde piksel olarak değerlendirilir.

Kod çözme sırasında, ColorTransformElement blok örneğinin kodu çözülür ve piksellerin ARGB değerlerine ters renk dönüşümü uygulanır. Daha önce de belirtildiği gibi, bu ters renk dönüşümü sadece kırmızı ve mavi kanallara ColorTransformElement değerleri ekliyor. Alfa ve yeşil kanallar olduğu gibi duruyor.

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şili Çıkarma Dönüşümü

Yeşil çıkarma dönüşümü, her pikselin kırmızı ve mavi değerlerinden yeşil değerleri çıkarır. Bu dönüşüm mevcut olduğunda kod çözücünün hem kırmızı hem de mavi değerlere yeşil değeri eklemesi gerekir. Bu dönüşümle ilişkili veri yoktur. Kod çözücü, ters dönüşümü aşağıdaki gibi uygular:

void AddGreenToBlueAndRed(uint8 green, uint8 *red, uint8 *blue) {
  *red  = (*red  + green) & 0xff;
  *blue = (*blue + green) & 0xff;
}

Bu dönüştürme işlemi, renk dönüşümü kullanılarak modellenebileceği için yedeklidir, ancak burada ek veri olmadığından yeşil çıkarma dönüşümü, tam renkli bir renk dönüşümüne kıyasla daha az bit kullanılarak kodlanabilir.

4.4 Renk Dizine Ekleme Dönüşümü

Çok sayıda benzersiz piksel değeri yoksa bir renk dizini dizisi oluşturmak ve piksel değerlerini, dizinin dizinleriyle değiştirmek daha verimli olabilir. Bunu, renk dizine ekleme dönüşümüyle başarır. (WebP kayıpsız bağlamında, buna özellikle palet dönüşümü adını vermeyiz, çünkü WebP'de kayıpsız kodlamada benzer ancak daha dinamik bir kavram vardır: 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 ARGB değerlerinden bir dizi oluşturur. 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, tüm kırmızı ve mavi değerleri ise 0 olarak ayarlanır.

Dönüştürme verileri, renk tablosu boyutunu ve renk tablosundaki girişleri içerir. Kod çözücü, rengi dizine ekleme dönüşüm verilerini aşağıdaki gibi 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ığı ve resim boyutu olmadan bir resim okunarak elde edilebilir ve genişliği 1 piksel ve genişliğinin color_table_size olduğu varsayılır. Renk tablosu, görüntü entropisini azaltmak için her zaman çıkarmayla kodlanır. Palet renklerinin deltaları genellikle renklerin kendilerinden çok daha az entropi içerir. Bu, küçük resimler için önemli tasarruflar sağlar. Kod çözme işleminde, renk tablosundaki her bir nihai renk, her bir ARGB bileşeninden önceki renk bileşeni değerlerinin ayrı ayrı eklenmesi ve sonucun en az anlamlı olan 8 bitinin saklanarak elde edilmesiyle elde edilebilir.

Resim için ters dönüşüm, sadece piksel değerlerini (renk tablosunun dizinleridir) gerçek renk tablosu değerleriyle değiştirmektir. Dizine ekleme işlemi, 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üçük olduğunda (16 renge eşit veya 16 renge eşitse) birkaç piksel tek bir piksel içinde paketlenir. Piksel grubu, birkaç (2, 4 veya 8) pikseli tek bir pikselde toplayarak resim genişliğini sırasıyla azaltır. Piksel gruplandırması, komşu piksellerin daha verimli bir ortak dağıtım entropi kodlamasına olanak tanır ve entropi koduna aritmetik kodlama benzeri 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 olur. 0 değeri, resim için herhangi bir 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 belirtir. 3 değeri, sekiz pikselin birleştirilmiş olduğunu ve her pikselin [0..1] aralığında olduğunu, yani ikili bir değere sahip olduğunu gösterir.

Değerler, yeşil bileşene aşağıdaki gibi yerleştirilir:

  • width_bits = 1: x ≠ 0 (mod 2) olduğunda her x değeri için x'teki yeşil değer, x / 2'de yeşil değerin en az anlamlı 4 bitine yerleştirilir ve x + 1'deki yeşil bir değer, x / 2'de 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 belirgin bitlerine göre konumlandırılır.
  • width_bits = 3: x ≠ 0 (mod 8) olan her x değeri için x'teki yeşil değer, x / 8'de 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 göre konumlandırılır.

Bu dönüşüm okunduktan sonra image_width, width_bits tarafından alt örneklendirildi. Bu durum, sonraki dönüşümlerin 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 Resim Verileri

Resim verileri, tarama satırı sırasındaki piksel değerleri dizisidir.

5.1 Resim Verilerinin Rolleri

Resim verilerini beş farklı rolde kullanırız:

  1. ARGB resmi: Resmin gerçek piksellerini depolar.
  2. Entropi resmi: Meta ön ek kodlarını depolar (bkz. "Meta Önek Kodlarının Şifresini Çözme").
  3. Tahmin aracı görüntüsü: Tahmin aracı dönüşümü için meta verileri depolar (bkz. "Tahmin Aracı Dönüşümü").
  4. Renk dönüştürme resmi: Resmin farklı blokları için ColorTransformElement değerleri ("Renk Dönüşümü" ile tanımlanır) tarafından oluşturulur.
  5. Renk dizine ekleme resmi: Renk dizine ekleme dönüşümü için meta verileri depolayan color_table_size boyutunda bir dizi (en fazla 256 ARGB değeri) ("Renk Dizine Ekleme Dönüşümü" bölümüne bakın).

5.2 Resim Verilerini Kodlama

Resim verilerinin kodlaması, rolünden bağımsızdır.

Resim önce sabit boyutlu bir blok grubuna (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: Entropi kodunu depolamanın maliyeti vardır. İstatistiksel olarak benzer bloklar bir entropi kodunu paylaşıyorsa bu maliyet en aza indirgenebilir ve böylece, bu kod yalnızca bir kez saklanabilir. Örneğin, kodlayıcı, istatistiksel özelliklerini kullanarak benzer blokları kümeleyerek veya resmi kodlamak için gereken toplam bit miktarını azalttığında rastgele seçilmiş bir küme çiftini sürekli olarak birleştirerek benzer blokları bulabilir.

Her piksel olası üç yöntemden biri kullanılarak kodlanır:

  1. Ön ek kodlu sabit değerler: Her bir kanal (yeşil, kırmızı, mavi ve alfa) bağımsız olarak entropi kodlanır.
  2. LZ77 geri referansı: Resmin başka bir yerinden bir piksel dizisi kopyalanır.
  3. Renk önbellek kodu: Yakın zamanda görülen bir rengin kısa çarpımsal karma kodunu (renk önbellek dizini) kullanma.

Aşağıdaki alt bölümlerde bunların her biri ayrıntılı olarak açıklanmaktadır.

5.2.1 Önek Kodlu Değişmez Değerler

Piksel, önek kodlu yeşil, kırmızı, mavi ve alfa (bu sırayla) değerleri olarak depolanır. Ayrıntılar için Bölüm 6.2.3'e bakın.

5.2.2 LZ77 Geriye Dönük Referans

Geriye referanslar uzunluk ve mesafe kodu öğelerinden oluşur:

  • Uzunluk, tarama satırı sırasında kaç pikselin kopyalanacağını belirtir.
  • Mesafe kodu, piksellerin kopyalanacağı önceden görülen bir pikselin konumunu belirten bir sayıdır. Tam eşleme aşağıda açıklanmıştır.

Uzunluk ve mesafe değerleri, LZ77 önek kodlaması kullanılarak saklanır.

LZ77 ön ek kodlaması, büyük tam sayı değerlerini iki bölüme ayırır: önek kodu ve ekstra bitler. Önek kodu bir entropi kodu kullanılarak, ekstra bitler ise (entropi kodu olmadan) oldukları gibi depolanır.

Rasyonel: Bu yaklaşım, entropi kodu için depolama gereksinimini azaltır. Ayrıca, büyük değerler genellikle nadir görülür. Bu nedenle, resimdeki çok az değer için ekstra bitler kullanılır. Böylece, bu yaklaşım toplamda daha iyi sıkıştırma ile sonuçlanır.

Aşağıdaki tabloda, farklı değer aralıklarını depolamak için kullanılan ön ek kodları ve ekstra bitler gösterilmektedir.

Değer aralığı Önek kodu Ekstra bit
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

Ön ek kodundan bir (uzunluk veya mesafe) değeri elde etmek için 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 mesafe kodu, piksellerin kopyalanacağı önceden görülen bir pikselin konumunu belirten bir sayıdır. Bu alt bölüm, bir mesafe kodu ile önceki bir pikselin konumu arasındaki eşlemeyi tanımlar.

120'den büyük mesafe kodları, piksel mesafesini tarama satırı sırasında gösterir ve uzaklığı 120 olarak ayarlar.

En küçük mesafe kodları [1..120] özeldir ve geçerli pikselin yakın bir mahallesi için ayrılmıştır. Bu mahalle 120 pikselden oluşur:

  • Geçerli pikselin 1 ila 7 satır üzerinde olan ve geçerli pikselin solunda en fazla 8 sütun veya sağ tarafında en fazla 7 sütun olan pikseller. [Bu tür piksellerin toplam sayısı = 7 * (8 + 1 + 7) = 112].
  • Geçerli pikselle aynı satırda bulunan ve geçerli pikselin solunda en fazla 8 sütun bulunan pikseller. [8 bu tür pikseller].

Mesafe kodu distance_code ile komşu piksel ofseti (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, mesafe kodu 1, komşu piksel için (0, 1) ofseti, yani geçerli pikselin üzerindeki piksel (X yönünde 0 piksel, Y yönünde 1 piksel fark) belirtir. Benzer şekilde, mesafe kodu 3 sol üst pikseli belirtir.

Kod çözücü, bir mesafe kodunu (distance_code) aşağıdaki şekilde tarama satırı sipariş mesafesine dist 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şlemedir, image_width ise resmin piksel cinsinden genişliğidir.

5.2.3 Renk Önbelleği Kodlaması

Renk önbelleği, resimde son kullanılan bir renk grubunu depolar.

Rasyonalite: Bu şekilde, son kullanılan renkler bazen diğer iki yöntemi (5.2.1 ve 5.2.2'de açıklanmıştır) kullanarak yayılmalarından daha etkili olarak ele alınabilir.

Renk önbellek kodları aşağıdaki gibi depolanır. Öncelikle, renk önbelleğinin kullanılıp kullanılmadığını gösteren 1 bitlik bir değer vardır. Bu bit 0 ise renk önbellek kodu olmaz ve bu kodlar yeşil simgeler ile uzunluk ön eki kodlarının kodunu çözen ön ek kodunda iletilmez. Ancak bu bit 1 ise bundan sonra renk önbellek 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]. Uyumlu kod çözücüler, diğer değerler için bozuk bir bit akışı belirtmelidir.

Renk önbelleği, color_cache_size boyutunda bir dizidir. Her giriş bir ARGB rengi saklar. Renkler (0x1e35a7bd * color) >> (32 - color_cache_code_bits) tarafından dizine eklenir. Renk önbelleğinde yalnızca bir arama yapılır; çakışma çözümü yoktur.

Bir resmin kodunu çözmenin veya kodlamanın başlangıcında, tüm renk önbelleği değerlerindeki tüm girişler sıfır olarak ayarlanır. Renk önbellek kodu, kod çözme sırasında bu renge dönüştürülür. Renk önbelleğinin durumu, geriye dönük referansla veya sabit değerler olarak üretilmiş her pikselin akışta göründükleri sırayla önbelleğe eklenerek korunur.

6 Entropi Kodu

6.1 Genel Bakış

Verilerin çoğu standart önek kodu kullanılarak kodlanır. Dolayısıyla, kodlar, gerçek önek kodlarının aksine ön ek kodu uzunlukları göndererek iletilir.

Özellikle, bu biçimde uzamsal olarak varyant önek kodlaması kullanılır. Başka bir deyişle, resmin farklı blokları potansiyel olarak farklı entropi kodları kullanabilir.

Rasyonel: Resmin farklı alanları farklı özelliklere sahip olabilir. Böylece, farklı entropi kodları kullanmalarına izin vermek daha fazla esneklik ve potansiyel olarak daha iyi sıkıştırma sağlar.

6.2 Ayrıntılar

Kodlanmış resim verileri birkaç bölümden oluşur:

  1. Ön ek kodlarının kodunu çözme ve oluşturma.
  2. Meta ön ek kodları.
  3. Entropi kodlu resim verileri.

Herhangi bir piksel (x, y) için bu pikselle ilişkilendirilmiş beş ön ek kodu grubu vardır. Bu kodlar (bit akış sırasına göre):

  • 1. önek kodu: Yeşil kanal, geriye dönük referans uzunluğu ve renk önbelleği için kullanılır.
  • 2, 3 ve 4 numaralı önek kodu: Sırasıyla kırmızı, mavi ve alfa kanalları için kullanılır.
  • 5. önek kodu: Geriye referans mesafesi için kullanılır.

Bu ayardan sonra bu gruba önek kodu grubu diyoruz.

6.2.1 Önek Kodlarının Şifresini Çö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 1 bitlik bir değerle belirtilir.

  • Bu bit 1 ise basit bir kod uzunluğu kodu kullanılır.
  • Bu bit 0 ise normal kod uzunluğu kodudur.

Her iki durumda da, hâlâ akışın parçası olan kullanılmamış kod uzunlukları olabilir. Bu verimsiz olabilir ancak biçim tarafından izin verilir. Açıklanan ağaç tam bir ikili ağaç olmalıdır. Tek yapraklı düğüm, eksiksiz bir ikili ağaç olarak kabul edilir ve basit kod uzunluk kodu veya normal kod uzunluğu kodu kullanılarak kodlanabilir. Normal kod uzunluğu kodunu kullanarak tek bir yaprak düğümünü kodlarken, biri hariç tüm kod uzunluğu sıfır olur ve tek yapraklı düğüm değeri, tek yapraklı düğüm ağacı kullanıldığında hiç bit bitmese bile 1 uzunluğuyla işaretlenir.

Basit Kod Uzunluğu Kodu

Bu varyant, [0..255] aralığında 1 kod uzunluğuna sahip 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ı dolaylı olarak sıfırdır.

İlk bit, simge sayısını gösterir:

int num_symbols = ReadBits(1) + 1;

Sembol değerleri aşağıda verilmiştir.

İlk 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. İkinci simge (varsa), her zaman [0..255] aralığında olduğu varsayılır ve 8 bit kullanılarak kodlanı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 simge farklı olmalıdır. Yinelenen simgelere izin verilir ancak verimsizdir.

Not: Diğer bir özel durum da tüm ön ek kodu uzunluklarının sıfır (boş bir ön ek kodu) olmasıdır. Örneğin, geriye dönük referans yoksa mesafe için bir önek kodu boş olabilir. Benzer şekilde, aynı meta ön ek kodu içindeki tüm pikseller renk önbelleği kullanılarak oluşturuluyorsa alfa, kırmızı ve mavi ön ek kodları boş olabilir. Ancak, boş ön ek kodları tek bir 0 sembolünü içerenler olarak kodlanabileceğinden bu durum özel işlem gerektirmez.

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ı, önek kodları kullanılarak kodlanır. Alt düzey kod uzunlukları (code_length_code_lengths) önce okunmalıdır. Bunların geri kalanı code_length_code_lengths (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 maksimum farklı okuma sembolü sayısı (max_symbol) kendi 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, simge türü için alfabenin boyutundan büyükse bit akışı geçersizdir.

Daha sonra code_length_code_lengths kullanılarak bir önek tablosu oluşturulur ve max_symbol kod uzunluğuna kadar okuma yapmak için kullanılır.

  • Kod [0..15], değişmez kod uzunluklarını gösterir.
    • 0 değeri, hiçbir sembolün kodlanmadığı anlamına gelir.
    • [1..15] değerleri, ilgili kodun bit uzunluğunu belirtir.
  • Kod 16, sıfır olmayan önceki değeri [3..6] kez, yani 3 + ReadBits(2) kez tekrar eder. Kod 16 sıfır olmayan bir değer yayınlanmadan önce kullanılırsa 8 değeri tekrarlanır.
  • Kod 17, sıfırlar halinde [3..10] şeklinde bir dizi yapar, yani 3 + ReadBits(3) kez.
  • Kod 18, sıfırlar halinde [11..138], yani 11 + ReadBits(7) kez seri yayınlar.

Kod uzunlukları okunduktan sonra, ilgili alfabe boyutları kullanılarak her bir sembol türü (A, R, G, B ve mesafe) için bir önek kodu oluşturulur.

Normal Kod Uzunluğu Kodu tam bir karar ağacını kodlamalıdır. Diğer bir deyişle, sıfır olmayan tüm kodlar için 2 ^ (-length) toplamı tam olarak bir olmalıdır. Bununla birlikte, bu kuralın bir istisnası vardır: tek yapraklı düğüm ağacı. Bu ağaçta yaprak düğümü değeri 1, diğer değerler 0 olarak işaretlenir.

6.2.2 Meta Önek Kodlarının Şifresini Çözme

Daha önce belirtildiği gibi bu biçim, resmin farklı blokları için farklı ön ek kodlarının kullanılmasına olanak tanır. Meta ön ek kodları, resmin farklı bölümlerinde hangi önek kodlarının kullanılacağını tanımlayan dizinlerdir.

Meta ön ek kodları yalnızca resim, bir ARGB resminin rolünde kullanılırken kullanılabilir.

Meta ön ek kodları için 1 bitlik değerle belirtilen iki olasılık vardır:

  • Bu bit sıfırsa resmin her yerinde yalnızca bir meta ön ek kodu kullanılır. Başka veri depolanmaz.
  • Bu bit birse, resimde birden çok meta önek kodu kullanılır. Bu meta önek kodları, entropi resmi olarak depolanır (aşağıda açıklanmıştır).

Pikselin kırmızı ve yeşil bileşenleri, ARGB resminin belirli bir bloğunda kullanılan 16 bitlik meta ön ek kodunu tanımlar.

Entropi Resmi

Entropi resmi, resmin farklı bölümlerinde hangi ön ek kodlarının kullanıldığını tanımlar.

İlk 3 bit, prefix_bits değerini içerir. Entropi görüntüsünün boyutları prefix_bits parametresinden 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şlik prefix_image_width ve yükseklik prefix_image_height olan bir entropi resmi içerir.

Meta Önek Kodlarının Yorumlanması

ARGB görüntüsündeki ön ek kodu gruplarının sayısı, entropi resminden en büyük meta ön ek kodu bulunarak elde edilebilir:

int num_prefix_groups = max(entropy image) + 1;

Burada max(entropy image), entropi resminde depolanan en büyük ön ek kodunu gösterir.

Her ön ek kodu grubu beş ön ek kodu içerdiği için toplam ön ek kodu sayısı şöyle olur:

int num_prefix_codes = 5 * num_prefix_groups;

ARGB resminde bir piksel (x, y) verildiğinde, aşağıdaki gibi kullanılacak ilgili ön ek 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];

Burada, beş ön ek kodu içeren PrefixCodeGroup yapısının varlığını kabul ettik. Ayrıca prefix_code_groups, PrefixCodeGroup dizisidir (num_prefix_groups boyutunda).

Kod çözücü daha sonra, "Entropi Kodlu Resim Verilerinin Kodunu Çözme" bölümünde açıklandığı gibi pikselin (x, y) kodunu çözmek için prefix_group ön ek kodu grubunu kullanır.

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 ön ek kodu grubunu tanımlar (son bölümde açıklandığı gibi). Önek kodu grubu dikkate alındığında, piksel aşağıdaki gibi okunur ve kodu çözülür.

Sonra, 1 numaralı önek kodunu kullanarak bit akışından S sembolünü okuyun. S'nin, 0-(256 + 24 + color_cache_size- 1) aralığındaki herhangi bir tam sayı olduğunu unutmayın.

S'nin yorumlanması değeri bağlıdır:

  1. S < 256 ise
    1. Yeşil bileşen olarak S'yi kullanın.
    2. Ön ek kodu 2'yi kullanarak bit akışından kırmızı okuyun.
    3. 3. önek kodunu kullanarak bit akışından mavi okuyun.
    4. 4 numaralı önek kodunu kullanarak bit akışından alfayı okuyun.
  2. S >= 256 ve S < 256 + 24 ise
    1. Uzunluk önek kodu olarak S - 256'yı kullanın.
    2. Bit akışından uzunluk için ekstra bitleri okur.
    3. Uzunluk önek kodundan ve okunan ekstra bitten L geriye referans uzunluğunu belirleyin.
    4. Ön ek kodunu #5 kullanarak bit akışından uzaklık önek kodunu okuyun.
    5. Bit akışına olan mesafe için ekstra bitleri okur.
    6. Uzaklık önek kodundan ve okunan ekstra bitlerden geriye dönük referans mesafesi D'yi belirleyin.
    7. Mevcut konumdan başlayan piksel dizisinden D piksel değeri çıkarılarak L piksellerini (tarama satırı sırasında) kopyalayın.
  3. S >= 256 + 24 ise
    1. Renk önbelleğine dizin olarak S - (256 + 24) değerini kullanın.
    2. İlgili dizindeki renk önbelleğinden ARGB rengi alın.

7 Formatın Genel Yapısı

Aşağıda, Artırılmış Backus-Naur Formu'ndaki (ABNF) RFC 5234 RFC 7405'teki biçimi görebilirsiniz. Tüm ayrıntıları kapsamaz. Resmin sonu (EOI) yalnızca piksel sayısına (resim_genişliği * resim_yüksekliği) kodlanır.

*element değerinin, element işlevinin 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, ikili 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 örnek adım sırası verilmiştir:

RIFF-header image-size %b1 subtract-green-tx
%b1 predictor-tx %b0 color-cache-info
%b0 prefix-codes lz77-coded-image