WebP लॉसलेस बिटस्ट्रीम के लिए खास जानकारी

जरकी अलाकुइजाला, पीएच॰डी॰, Google LLC, 09-03-2023

खास जानकारी

WebP लॉसलेस, ARGB इमेज को लॉसलेस कंप्रेस करने का एक इमेज फ़ॉर्मैट है. कॉन्टेंट बनाने लॉसलेस फ़ॉर्मैट, पिक्सल वैल्यू को ठीक से सेव और पहले जैसा करता है. इनमें, ये वैल्यू भी शामिल हैं पूरी तरह पारदर्शी पिक्सल के लिए कलर वैल्यू. क्रम के मुताबिक लागू होने वाला यूनिवर्सल एल्गोरिदम डेटा कंप्रेशन (LZ77), प्रीफ़िक्स कोडिंग, और कलर कैश मेमोरी का इस्तेमाल इन कामों के लिए किया जाता है बल्क डेटा को कंप्रेस करना. PNG की तुलना में तेज़ी से डिकोड करने की स्पीड दिखाया जाता है. साथ ही, इसका इस्तेमाल करके कंप्रेस की जा सकने वाली रेंज 25% ज़्यादा होती है को PNG फ़ॉर्मैट में एक्सपोर्ट किया जा सकता है.

1 परिचय

इस दस्तावेज़ में, WebP लॉसलेस के कंप्रेस किए गए डेटा को दिखाने के बारे में बताया गया है इमेज. इसका मकसद, WebP लॉसलेस एन्कोडर के लिए पूरी जानकारी देना है और डिकोडर लागू करना.

इस दस्तावेज़ में हमने बताया है कि बिटस्ट्रीम को पढ़ेंगे और रीडिंग बिट के लिए किसी फ़ंक्शन की मौजूदगी का अनुमान लगाने की कोशिश करेंगे, ReadBits(n). बाइट को उस स्ट्रीम के सामान्य क्रम में पढ़ा जाता है जिसमें शामिल है साथ ही, हर बाइट के बिट को बिट के क्रम में सबसे कम क्रम में पढ़ा जाता है. टास्क कब शुरू होगा कई बिट एक साथ पढ़े जाते हैं, तो पूर्णांक से मूल डेटा को मूल क्रम में रखा जाता है. लौटाए गए प्रॉडक्ट की सबसे अहम बिट पूर्णांक, ओरिजनल डेटा के सबसे अहम हिस्से भी होते हैं. इसलिए, स्टेटमेंट

b = ReadBits(2);

नीचे दिए गए दो स्टेटमेंट के बराबर है:

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

हम मानते हैं कि अल्फ़ा, लाल, नीला, और हरा रंग के हर कॉम्पोनेंट जिसे 8-बिट बाइट का इस्तेमाल करके दिखाया जाता है. इससे जुड़े टाइप को हम uint8 के तौर पर बताते हैं. ऐप्लिकेशन ARGB के पूरे पिक्सल को uint32 टाइप से दिखाया जाता है, जो कि एक साइन नहीं किया गया है. 32 बिट वाला पूर्णांक. कोड में, पूरी तरह से बदल जाता है, तो ये वैल्यू इन बिट में कोडिफ़ाइड होती हैं: बिट में ऐल्फ़ा 31..24, लाल रंग के बिट 23..16, हरा बिट 15..8, और नीला बिट 7..0; हालांकि, फ़ॉर्मैट को लागू करने के लिए, संगठन में किसी दूसरे तरीके का इस्तेमाल किया जा सकता है.

बड़े पैमाने पर, WebP लॉसलेस इमेज में हेडर डेटा, जानकारी को बदलना, और इमेज से जुड़ा डेटा. हेडर में इमेज की चौड़ाई और ऊंचाई होती है. WebP फ़ॉर्मैट लॉसलेस इमेज एन्ट्रॉपी को कोड में बदला गया. बिटस्ट्रीम की रूपांतरण जानकारी में डेटा होता है संबंधित व्युत्क्रम ट्रांसफ़ॉर्म को लागू करने के लिए ज़रूरी है.

2 नामकरण

एआरजीबी
पिक्सल वैल्यू जिसमें ऐल्फ़ा, लाल, हरे, और नीले वैल्यू शामिल हों.
ARGB इमेज
दो डाइमेंशन वाला अरे, जिसमें ARGB पिक्सल मौजूद हों.
कलर कैश
हाल ही में इस्तेमाल किए गए रंगों को स्टोर करने के लिए, हैश के आधार पर तैयार किया गया छोटा अरे. उन्हें छोटे कोड से याद करते हैं.
कलर इंडेक्स करने वाली इमेज
रंगों की एक डाइमेंशन वाली इमेज, जिसे छोटे पूर्णांक का इस्तेमाल करके इंडेक्स किया जा सकता है (WebP लॉसलेस में 256 तक).
रंग बदलने वाली इमेज
दो-डाइमेंशन वाली सबरिज़ॉल्यूशन वाली इमेज, जिसमें रंग कॉम्पोनेंट.
दूरी मैप करना
पिक्सल के लिए सबसे छोटी वैल्यू रखने के लिए, LZ77 दूरी को बदलता है दो डाइमेंशन में आस-पास की जगह हो.
एन्ट्रॉपी इमेज
दो-डाइमेंशन वाली सबरिज़ॉल्यूशन वाली इमेज, जिससे पता चलता है कि किस एंट्रॉपी कोडिंग को करना चाहिए इसे इमेज में संबंधित वर्ग में इस्तेमाल किया जाना चाहिए, यानी हर पिक्सेल एक मेटा प्रीफ़िक्स कोड होना चाहिए.
LZ77
शब्दकोश पर आधारित स्लाइडिंग विंडो कंप्रेशन एल्गोरिदम, जो या तो उत्सर्जन करता है निशान या उन्हें पुराने प्रतीकों के क्रम के तौर पर पेश करता है.
मेटा प्रीफ़िक्स कोड
एक छोटा पूर्णांक (ज़्यादा से ज़्यादा 16 बिट), जो मेटा प्रीफ़िक्स में किसी एलिमेंट को इंडेक्स करता हो टेबल.
अनुमान लगाने वाली इमेज
दो-डाइमेंशन वाली सबरिज़ॉल्यूशन वाली इमेज, जो बताती है कि जगह की जानकारी का अनुमान कौनसा है का इस्तेमाल इमेज में किसी स्क्वेयर स्क्वेयर के लिए किया गया हो.
उपसर्ग कोड
एंट्रॉपी कोडिंग करने का एक क्लासिक तरीका, जिसमें कम बिट का इस्तेमाल किया जाता है अक्सर इस्तेमाल किए जाने वाले कोड के लिए.
प्रीफ़िक्स कोडिंग
बड़े पूर्णांकों को एंट्रॉपी करने का तरीका, जो पूर्णांक के कुछ बिट को कोड करते हैं एंट्रॉपी कोड का इस्तेमाल करके और बची हुई बिट को कोड करता है. इससे आपको हालांकि, एंट्रॉपी कोड की तुलना में छोटे एलिमेंट को मिलाकर बनाए गए में चिह्नों की रेंज बड़ी हो.
स्कैन-लाइन ऑर्डर
पिक्सल का प्रोसेसिंग ऑर्डर (बाएं से दाएं और ऊपर से नीचे), शुरू होता है ऊपर की ओर तीर के निशान से. पंक्ति पूरी होने के बाद, यहां से जारी रखें अगली पंक्ति के बाईं ओर मौजूद कॉलम पर क्लिक करें.

3 RIFF हेडर

हेडर की शुरुआत में आरआईएफ़ कंटेनर होता है. इसमें यह शामिल है ये 21 बाइट होने चाहिए:

  1. स्ट्रिंग 'RIFF'.
  2. डेटा ग्रुप की छोटी-छोटी वैल्यू, 32-बिट, जो पूरे साइज़ में होती है डेटा वाले हिस्से का टेक्स्ट, RIFF हेडर से कंट्रोल किया जाता है. आम तौर पर, यह इसके बराबर होता है पेलोड का साइज़ (फ़ाइल का साइज़ 8 बाइट से कम: 'RIFF' के लिए 4 बाइट आइडेंटिफ़ायर और वैल्यू को स्टोर करने के लिए 4 बाइट).
  3. स्ट्रिंग 'WEBP' (RIFF कंटेनर का नाम).
  4. स्ट्रिंग 'VP8L' (लॉसलेस-एन्कोडेड इमेज डेटा के लिए चारसीसी).
  5. लिटिल-एंडियन, 32-बिट की वैल्यू स्ट्रीम न करें.
  6. 1-बाइट का सिग्नेचर 0x2f.

बिटस्ट्रीम के पहले 28 बिट से इमेज की चौड़ाई और ऊंचाई की जानकारी मिलती है. चौड़ाई और ऊंचाई को 14-बिट पूर्णांक के तौर पर इस तरह डिकोड किया जाता है:

int image_width = ReadBits(14) + 1;
int image_height = ReadBits(14) + 1;

इमेज की चौड़ाई और ऊंचाई के लिए 14-बिट सटीक होने से, इमेज की ज़्यादा से ज़्यादा साइज़ WebP वाली लॉसलेस इमेज, जिसका साइज़ 16384 गुना16384 पिक्सल है.

Alphabet_is_used बिट सिर्फ़ एक संकेत है. इससे डिकोड करने पर कोई असर नहीं पड़ना चाहिए. इसे ऐसा होना चाहिए जब चित्र में सभी अल्फ़ा मान 255 हों, तो 0 पर सेट हो, और नहीं तो 1 पर सेट हो.

int alpha_is_used = ReadBits(1);

version_number 3 बिट का कोड है, जिसे 0 पर सेट करना ज़रूरी है. किसी अन्य वैल्यू को गड़बड़ी के रूप में नहीं देखा जाएगा.

int version_number = ReadBits(3);

4 ट्रांसफ़ॉर्म

ट्रांसफ़ॉर्म, इमेज डेटा में किए गए उलटे बदलाव हैं. इन्हें स्पेशल और कलर कोरिलेशन के आधार पर, बची हुई सिंबॉलिक एंट्रॉपी. वे अंतिम संपीड़न को और घना बना सकते हैं.

एक इमेज में चार तरह के बदलाव हो सकते हैं. 1 बिट का मतलब बदलाव की मौजूदगी. हर ट्रांसफ़ॉर्म को सिर्फ़ एक बार इस्तेमाल किया जा सकता है. कॉन्टेंट बनाने ट्रांसफ़ॉर्म का इस्तेमाल सिर्फ़ मुख्य-लेवल की एआरजीबी इमेज के लिए किया जाता है; सबरिज़ॉल्यूशन वाली इमेज (रंग बदलने वाली इमेज, एंट्रॉपी इमेज, और अनुमान लगाने वाली इमेज) में कोई ट्रांसफ़ॉर्म नहीं है, यहां तक कि रूपांतरण के अंत को दिखाने वाला 0 बिट भी नहीं.

आम तौर पर, शैनन एंट्रॉपी को कम करने के लिए एन्कोडर इन बदलावों का इस्तेमाल करता है पर क्लिक करें. साथ ही, डेटा को बदलने का फ़ैसला एंट्रॉपी के आधार पर लिया जा सकता है मिनिमाइज़ेशन.

while (ReadBits(1)) {  // Transform present.
  // Decode transform type.
  enum TransformType transform_type = ReadBits(2);
  // Decode transform data.
  ...
}

// Decode actual image data (Section 5).

अगर ट्रांसफ़ॉर्मेशन मौजूद है, तो अगले दो बिट से ट्रांसफ़ॉर्मेशन का टाइप तय होता है. ट्रांसफ़ॉर्म चार तरह के होते हैं.

enum TransformType {
  PREDICTOR_TRANSFORM             = 0,
  COLOR_TRANSFORM                 = 1,
  SUBTRACT_GREEN_TRANSFORM        = 2,
  COLOR_INDEXING_TRANSFORM        = 3,
};

ट्रांसफ़ॉर्म टाइप के बाद, ट्रांसफ़ॉर्म डेटा डाला जाता है. डेटा में यह शामिल है व्युत्क्रम रूपांतरण को लागू करने के लिए आवश्यक जानकारी और ट्रांसफ़ॉर्म टाइप का इस्तेमाल करने के लिए किया जा सकता है. व्युत्क्रम रूपांतरण उस क्रम में लागू किए जाते हैं, जो उन्हें बिटस्ट्रीम से पढ़ा जाता है, यानी, सबसे पहले आखिरी बार.

इसके बाद, हम डेटा में बदलाव करने के अलग-अलग तरीकों के बारे में बताते हैं.

4.1 अनुमान लगाने वाला बदलाव

एंट्रॉपी को कम करने के लिए, तथ्य का गलत इस्तेमाल करके अनुमान लगाने वाले ट्रांसफ़ॉर्म का इस्तेमाल किया जा सकता है आस-पास के पिक्सल अक्सर एक-दूसरे से जुड़े होते हैं. अनुमान लगाने वाले के बदलाव में, मौजूदा पिक्सल की वैल्यू का अनुमान, पहले से डिकोड किए गए पिक्सल (स्कैन-लाइन में) से लगाया जाता है क्रम) और सिर्फ़ रेज़िड्यूअल वैल्यू (असल - अनुमानित) को कोड में बदला जाता है. द ग्रीन Pixel का कॉम्पोनेंट तय करता है कि पर क्लिक करें. पूर्वानुमान मोड इस्तेमाल करने के लिए सुझाव. हम इमेज को स्क्वेयर में बांटते हैं और सभी पिक्सल को वर्ग समान अनुमान मोड का उपयोग करते हैं.

अनुमान के डेटा के पहले तीन बिट, संख्या में ब्लॉक की चौड़ाई और ऊंचाई तय करते हैं बिट में से.

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);

रूपांतरण डेटा में चित्र के प्रत्येक ब्लॉक के लिए पूर्वानुमान मोड होता है. यह एक सबरिज़ॉल्यूशन इमेज होती है, जिसमें पिक्सल का हरा कॉम्पोनेंट यह तय करता है कि 14 अनुमानों का इस्तेमाल सभी block_width * block_height पिक्सल के लिए किया जाता है ARGB इमेज का कोई खास ब्लॉक. इस सब-रिज़ॉल्यूशन वाली इमेज को इसका इस्तेमाल करके कोड में बदला गया है ये वही तकनीक हैं जो चैप्टर 5 में बताई गई हैं.

ब्लॉक कॉलम की संख्या transform_width का इस्तेमाल दो-डाइमेंशन में किया जाता है इंडेक्स करना. पिक्सल (x, y) के लिए, अलग-अलग फ़िल्टर ब्लॉक की गणना की जा सकती है इसके द्वारा पता:

int block_index = (y >> size_bits) * transform_width +
                  (x >> size_bits);

पूर्वानुमान वाले 14 अलग-अलग मोड उपलब्ध हैं. हर अनुमान मोड में, मौजूदा पिक्सल वैल्यू का अनुमान आस-पास के एक या उससे ज़्यादा उन पिक्सल से लगाया जाता है जिनकी वैल्यू पहले से पता है.

हमने मौजूदा पिक्सल (P) के आस-पास के पिक्सल (TL, T, TR, और L) को इस तरह चुना है अनुसरण करता है:

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

इसमें TL का मतलब है, ऊपर बाईं ओर, T का मतलब है सबसे ऊपर, TR का मतलब ऊपर दाईं ओर, और L का मतलब है बाईं ओर. पर P, सभी O, TL, T, TR, और L पिक्सल के लिए मान का पूर्वानुमान लगाने के लिए, पहले से ही प्रोसेस कर दी गई है, और P पिक्सल और सभी X पिक्सल के बारे में जानकारी नहीं है.

पिछले आस-पास के पिक्सल को देखते हुए, अनुमान के लिए अलग-अलग मोड हैं परिभाषित किया गया है.

मोड मौजूदा पिक्सल के हर चैनल की अनुमानित वैल्यू
0 0xff000000 (ARGB में गहरे काले रंग को दिखाता है)
1 L
2 T
3 में कीमत
4 टीम लीडर
5 औसत2(औसत2(L, TR), T)
6 औसत2(L, TL)
7 औसत2(L, T)
8 औसत2(टीएल, टी)
9 औसत2(T, TR)
10 औसत2(औसत2(L, TL), औसत2(T, TR))
11 चुनें(L, T, TL)
12 ClampAddSubtractFull(L, T, TL)
13 ClampAddSubtractHalf(Average2(L, T), TL)

हर एआरजीबी कॉम्पोनेंट के लिए, Average2 को नीचे बताए गए तरीके से बताया गया है:

uint8 Average2(uint8 a, uint8 b) {
  return (a + b) / 2;
}

सेल के अनुमान लगाने वाले टूल को इस तरह परिभाषित किया गया है:

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 और ClampAddSubtractHalf फ़ंक्शन किए गए नीचे बताए गए तरीके से हर एआरजीबी कॉम्पोनेंट के लिए:

// 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);
}

कुछ बॉर्डर पिक्सल के लिए खास हैंडलिंग नियम होते हैं. अगर कोई इन पिक्सल के लिए मोड [0..13] चाहे जो भी हो, अनुमान लगाने वाले के ट्रांसफ़ॉर्म ऐक्शन इमेज के सबसे ऊपर बाएं पिक्सल की अनुमानित वैल्यू 0xff000000 है, सभी सबसे ऊपर वाली पंक्ति के पिक्सल L-pixel हैं और सबसे बाईं ओर के कॉलम के सभी पिक्सल हैं टी-पिक्सल.

सबसे दाईं ओर के कॉलम पर पिक्सल के लिए टीआर-पिक्सल को ठीक करना असाधारण. सबसे दाईं ओर मौजूद कॉलम के पिक्सल का अनुमान, मोड का इस्तेमाल करके लगाया जाता है [0..13], बिलकुल वैसे ही जैसे पिक्सल बॉर्डर पर नहीं होता, बल्कि उसी पंक्ति का उपयोग किया जाता है, जो वर्तमान पिक्सेल के बजाय TR-pixel के रूप में की जाती है.

आखिरी पिक्सल वैल्यू, अनुमानित वैल्यू के हर चैनल को जोड़कर मिलती है कोड में बदले गए रेज़िड्यूअल वैल्यू में बदलना होगा.

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 रंग बदलना

रंग रूपांतरण का लक्ष्य प्रत्येक के R, G, और B मानों को सजाना है Pixel है. कलर ट्रांसफ़ॉर्म की वैल्यू में हरा (G) वैल्यू बरकरार रहती है. इससे, हरे मान के आधार पर लाल (R) मान और नीले (B) मान के आधार पर हरे मान पर और फिर लाल मान पर.

जैसा कि अनुमान लगाने वाले के बदलने की स्थिति में होता है, पहले इमेज को ब्लॉक में शामिल होती है और किसी ब्लॉक में सभी पिक्सल के लिए इसी ट्रांसफ़ॉर्म मोड का इस्तेमाल किया जाता है. इसके लिए और हर ब्लॉक में, तीन तरह के रंग बदलने वाले एलिमेंट होते हैं.

typedef struct {
  uint8 green_to_red;
  uint8 green_to_blue;
  uint8 red_to_blue;
} ColorTransformElement;

वास्तविक रंग रूपांतरण एक रंग रूपांतरण डेल्टा निर्धारित करके किया जाता है. कॉन्टेंट बनाने रंग बदलने वाले डेल्टा ColorTransformElement पर निर्भर करते हैं, जो एक जैसा है सभी पिक्सल के लिए. इसके दौरान डेल्टा को घटा दिया जाता है रंग में बदलाव करने की सुविधा देता है. इससे उलटा रंग बदलने पर सिर्फ़ डेल्टा की संख्या बढ़ती है.

रंग बदलने वाले फ़ंक्शन को इस तरह परिभाषित किया गया है:

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 की गणना करने के लिए, साइन किए गए 8-बिट वाले पूर्णांक का इस्तेमाल किया जाता है. 3.5-फ़िक्स्ड-पॉइंट नंबर और साइन किया गया 8-बिट आरजीबी कलर चैनल (c) [-128..127] और इसकी परिभाषा इस तरह से दी गई है:

int8 ColorTransformDelta(int8 t, int8 c) {
  return (t * c) >> 5;
}

8-बिट अनसाइन्ड रिप्रज़ेंटेशन (uint8) से 8-बिट साइन किए गए कन्वर्ज़न में कन्वर्ज़न ColorTransformDelta() को कॉल करने से पहले, एक (int8) ज़रूरी है. साइन किया गया मान को 8-बिट दो की पूरक संख्या (यानी: uint8 रेंज) के तौर पर समझा जाना चाहिए [128..255] को इसकी बदली गई int8 वैल्यू की [-128..-1] रेंज में मैप किया गया है.

गुणा को ज़्यादा सटीक (कम से कम 16-बिट के साथ) का इस्तेमाल करके किया जाना है प्रिसिज़न). शिफ़्ट कार्रवाई की साइन एक्सटेंशन प्रॉपर्टी इससे कोई फ़र्क़ नहीं पड़ता यहां; नतीजे में से सिर्फ़ सबसे नीचे के 8 बिट का इस्तेमाल किया जाता है. साथ ही, एक्सटेंशन शिफ़्टिंग और बिना साइन इन किए शिफ़्टिंग का तरीका एक-दूसरे से मेल खाता है.

अब हम, रंग बदलने से जुड़े डेटा के कॉन्टेंट के बारे में बताते हैं, ताकि डिकोडिंग लागू की जा सके व्युत्क्रम रंग पूरी तरह बदल जाता है और मूल लाल और नीले रंग की वैल्यू को वापस ला देता है. कॉन्टेंट बनाने कलर ट्रांसफ़ॉर्म डेटा के पहले तीन बिट में, जैसे कि अनुमान लगाने वाले के बदलाव की तरह इमेज ब्लॉक में बिट की संख्या:

int size_bits = ReadBits(3) + 2;
int block_width = 1 << size_bits;
int block_height = 1 << size_bits;

कलर ट्रांसफ़ॉर्म डेटा के बाकी हिस्से में ColorTransformElement शामिल है इंस्टेंस, इमेज के हर ब्लॉक से जुड़े. हर ColorTransformElement 'cte' को सबरिज़ॉल्यूशन वाली इमेज में पिक्सल माना जाता है जिसका ऐल्फ़ा कॉम्पोनेंट 255 है, लाल रंग का कॉम्पोनेंट cte.red_to_blue, हरा है कॉम्पोनेंट cte.green_to_blue है और नीला कॉम्पोनेंट cte.green_to_red है.

डिकोड करने के दौरान, ब्लॉक के ColorTransformElement इंस्टेंस डिकोड किए जाते हैं और इनवर्स कलर ट्रांसफ़ॉर्म, पिक्सल की ARGB वैल्यू पर लागू होता है. जैसे जैसा कि हमने पहले बताया है, कि इन्वर्स कलर ट्रांसफ़ॉर्मेशन सिर्फ़ लाल और नीले चैनलों के लिए ColorTransformElement वैल्यू. ऐल्फ़ा और हरा रंग चैनलों में कोई बदलाव नहीं होता.

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 ग्रीन ट्रांसफ़ॉर्म को घटाएं

हरे रंग का घटाव निकालने पर, हरे रंग के मान को लाल और नीले रंग के मान से घटा दिया जाता है हर पिक्सल में बदलाव कर सकते हैं. जब यह ट्रांसफ़ॉर्म मौजूद होता है, तो डिकोडर को हरा रंग लाल और नीले दोनों मानों के लिए मान डालें. इससे जुड़ा कोई डेटा नहीं है पूरी तरह से बदलें. डिकोडर, व्युत्क्रम रूपांतरण को इस तरह लागू करता है:

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

यह ट्रांसफ़ॉर्म गैर-ज़रूरी है, क्योंकि इसे कलर ट्रांसफ़ॉर्म का इस्तेमाल करके मॉडल किया जा सकता है, लेकिन चूंकि यहां कोई अतिरिक्त डेटा नहीं है, इसलिए हरे रंग का घटाव किया गया रूपांतरण फ़ुल-ब्लेउन कलर ट्रांसफ़ॉर्म की तुलना में कम बिट का इस्तेमाल करके कोड किया गया.

4.4 रंग को इंडेक्स करने से जुड़े बदलाव

अगर बहुत ज़्यादा यूनीक पिक्सल वैल्यू नहीं हैं, तो बेहतर होगा कि एक कलर इंडेक्स अरे को सेट करें और अरे के इंडेक्स से पिक्सल वैल्यू को बदलें. रंग इंडेक्स करने में बदलाव होने की वजह से ऐसा किया जा सकता है. (WebP लॉसलेस के संदर्भ में, हम खास तौर पर, इसे पैलेट ट्रांसफ़ॉर्म न कहें, क्योंकि इससे मिलता-जुलता है, लेकिन डाइनैमिक कॉन्सेप्ट, WebP लॉसलेस एन्कोडिंग में मौजूद है: कलर कैश.)

रंग इंडेक्स करने की सुविधा, इमेज. अगर वह संख्या, थ्रेशोल्ड (256) से कम है, तो यह उनकी एक कैटगरी बनाता है ARGB वैल्यू का इस्तेमाल किया जाता है. इसके बाद, पिक्सल वैल्यू को संबंधित इंडेक्स: पिक्सल के हरे चैनल को इंडेक्स में, सभी ऐल्फ़ा वैल्यू 255 और लाल और नीले रंग की सभी वैल्यू 0 पर सेट होती हैं.

रूपांतरण डेटा में रंग तालिका का आकार और प्रविष्टियां रंगीन होती हैं टेबल. डिकोडर, कलर इंडेक्स करने से डेटा को इस तरह बदलता है:

// 8-bit value for the color table size
int color_table_size = ReadBits(8) + 1;

कलर टेबल को इमेज स्टोरेज फ़ॉर्मैट का इस्तेमाल करके सेव किया जाता है. कलर टेबल को RIFF हेडर, चित्र के आकार, और 1 पिक्सेल की ऊंचाई और color_table_size की चौड़ाई मानकर बदल जाता है. इमेज की एन्ट्रॉपी को कम करने के लिए, कलर टेबल में हमेशा घटाव की सुविधा का इस्तेमाल किया जाता है. डेल्टा पैलेट रंगों में आम तौर पर रंगों की तुलना में बहुत कम एंट्रॉपी होती है इससे छोटी इमेज के लिए भारी बचत होती है. डिकोड करने में, कलर टेबल के हर आखिरी रंग को, पिछले कलर टेबल में हर ARGB कॉम्पोनेंट के हिसाब से, कलर कॉम्पोनेंट की अलग-अलग वैल्यू सबमिट की जाती हैं. साथ ही, इन वैल्यू को सबसे कम सेव किया जाता है नतीजे के अहम 8 बिट.

इमेज का इनवर्स ट्रांसफ़ॉर्म सिर्फ़ पिक्सल वैल्यू को बदल रहा है ( कलर टेबल के इंडेक्स) हैं. इंडेक्स करना ARGB रंग के हरे घटक के आधार पर किया जाता है.

// Inverse transform
argb = color_table[GREEN(argb)];

अगर इंडेक्स color_table_size के बराबर या उससे बड़ा है, तो 'आरजीबी' रंग की वैल्यू यह 0x00000000 (पारदर्शी काला) पर सेट होना चाहिए.

जब कलर टेबल छोटी होती है (16 के बराबर या उससे कम), तो कई पिक्सल एक पिक्सल में बंडल किए गए हों. Pixel बंडलिंग में कई (2, 4 या 8) पैक होते हैं एक पिक्सल में पिक्सल करें, जिससे इमेज की चौड़ाई कम हो जाए. पिक्सल बंडलिंग से, ज़्यादा बेहतर तरीके से जॉइंट डिस्ट्रिब्यूशन की एंट्रॉपी कोडिंग में मदद मिलती है आस-पास के पिक्सल शामिल हैं और इससे अंकगणितीय कोडिंग जैसे कुछ फ़ायदे मिलते हैं एंट्रॉपी कोड का इस्तेमाल किया जा सकता है, लेकिन इसका इस्तेमाल सिर्फ़ तब किया जा सकता है, जब यूनीक वैल्यू 16 या उससे कम हों.

color_table_size बताता है कि कितने पिक्सल जोड़े गए हैं:

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 की वैल्यू 0, 1, 2 या 3 होती है. 0 वैल्यू का मतलब है कि कोई पिक्सल नहीं है चित्र को बंडल करना होगा. वहीं, अगर वैल्यू 1 है, तो इसका मतलब है कि दो पिक्सल मिला है, और हर पिक्सल की रेंज [0..15] होती है. वैल्यू 2 होने का मतलब है कि चार पिक्सल मिल जाते हैं और हर पिक्सल की रेंज [0..3] होती है. तीन की वैल्यू यह बताता है कि आठ पिक्सल मिले-जुले हैं और हर पिक्सल की रेंज [0..1] होती है, यानी, एक बाइनरी मान.

वैल्यू को हरे रंग के कॉम्पोनेंट में इस तरह से पैक किया जाता है:

  • width_bits = 1: हर x वैल्यू के लिए, जहां x Permissions 0 (मॉड 2) के लिए हरा रंग x पर वैल्यू को चार सबसे कम ज़रूरी बिट में रखा जाता है वैल्यू x / 2 है और x + 1 पर हरा वैल्यू, x / 2 पर, हरे रंग की वैल्यू के चार सबसे अहम बिट.
  • width_bits = 2: हर x वैल्यू के लिए, जहां x Permissions 0 (मॉड 4) के लिए हरा रंग x पर मान को वैल्यू x / 4 है. साथ ही, x + 1 से x + 3 तक की हरी वैल्यू, x / 4 पर हरे मान के ज़्यादा महत्वपूर्ण बिट के लिए ऑर्डर करें.
  • width_bits = 3: हर x वैल्यू के लिए, जहां x Permissions 0 (मॉड 8) के लिए हरा रंग x पर मान हरे रंग के सबसे कम ज़रूरी बिट में रखा गया है वैल्यू x / 8 है. साथ ही, x + 1 से x + 7 तक की हरी वैल्यू, क्रम में लगी हैं x / 8 पर हरे रंग की वैल्यू के सबसे अहम बिट तक.

इस ट्रांसफ़ॉर्म को पढ़ने के बाद, image_width को width_bits ने सबसैंपल कर दिया है. यह होने वाले बदलावों के साइज़ पर असर डालता है. नए साइज़ का पता लगाने के लिए, DIV_ROUND_UP, जैसा कि पहले बताया गया है.

image_width = DIV_ROUND_UP(image_width, 1 << width_bits);

5 इमेज डेटा

इमेज डेटा, स्कैन-लाइन के क्रम में पिक्सल की वैल्यू का कलेक्शन होता है.

5.1 इमेज डेटा की भूमिकाएं

हम इमेज डेटा का इस्तेमाल पांच अलग-अलग भूमिकाओं में करते हैं:

  1. ARGB इमेज: इमेज के वास्तविक पिक्सल को सेव करती है.
  2. एंट्रॉपी इमेज: मेटा प्रीफ़िक्स कोड स्टोर करती है (देखें "मेटा प्रीफ़िक्स कोड की डिकोडिंग").
  3. अनुमान लगाने वाले की इमेज: अनुमान लगाने वाले के बदलाव के मेटाडेटा को स्टोर करती है (देखें "प्रेडिक्टर ट्रांसफ़ॉर्म").
  4. रंग बदलने वाली इमेज: ColorTransformElement वैल्यू से बनाया गया अलग-अलग ब्लॉक के लिए ("कलर ट्रांसफ़ॉर्म" में बताया गया है) पर क्लिक करें.
  5. रंग इंडेक्स करने वाली इमेज: color_table_size साइज़ का अरे (256 एआरजीबी तक) मान) रंग अनुक्रम में बदलाव के लिए मेटाडेटा संग्रहित करना (देखें) "कलर इंडेक्स करने का तरीका बदलना").

5.2 इमेज डेटा की एन्कोडिंग

इमेज डेटा को कोड में बदलने का तरीका, उसकी भूमिका से अलग होता है.

इमेज को पहले, तय साइज़ के ब्लॉक (आम तौर पर 16x16) में बांटा जाता है ब्लॉक). इनमें से हर ब्लॉक को उसके एंट्रॉपी कोड का इस्तेमाल करके मॉडल किया जाता है. साथ ही, कई ब्लॉक एक ही एंट्रॉपी कोड शेयर कर सकते हैं.

रायलाय: किसी एंट्रॉपी कोड को स्टोर करने के लिए शुल्क देना पड़ता है. इस लागत को कम किया जा सकता है अगर आंकड़ों के हिसाब से मिलते-जुलते ब्लॉक एक एंट्रॉपी कोड शेयर करते हैं, तो उस कोड को सेव किया जाता है का इस्तेमाल करें. उदाहरण के लिए, एन्कोडर एक जैसे ब्लॉक को क्लस्टर में बांटकर उन्हें ढूंढ सकता है या यादृच्छिक रूप से जोड़े जाने के लिए बार-बार क्लस्टर तब चुने जाते हैं, जब यह कोड में बदलने के लिए ज़रूरी बिट की कुल संख्या को कम करता है इमेज को हाइलाइट करें.

हर पिक्सल को कोड में बदलने के लिए, तीन संभावित तरीकों में से किसी एक का इस्तेमाल किया जाता है:

  1. प्रीफ़िक्स कोड वाली लिटरल वैल्यू: हर चैनल (हरा, लाल, नीला, और ऐल्फ़ा) अलग से कोड में बदला गया हो.
  2. LZ77 बैकवर्ड रेफ़रंस: पिक्सल का सीक्वेंस, इसमें कहीं और से कॉपी किया जाता है इमेज को हाइलाइट करें.
  3. कलर कैश कोड: एक छोटे मल्टीप्लिकेटिव हैश कोड (कलर कैश) का इस्तेमाल करना इंडेक्स).

इन सब-सेक्शन में, इनके बारे में पूरी जानकारी दी गई है.

5.2.1 प्रीफ़िक्स-कोडेड लिटरल

पिक्सेल को हरे, लाल, नीले और अल्फ़ा ( आदेश नहीं है). इनके लिए सेक्शन 6.2.3 देखें विवरण.

5.2.2 LZ77 बैकवर्ड रेफ़रंस

बैकवर्ड रेफ़रंस, length और दूरी के कोड के टपल होते हैं:

  • लंबाई से पता चलता है कि स्कैन-लाइन के क्रम में कितने पिक्सल कॉपी किए जाने हैं.
  • दूरी का कोड वह संख्या है जो पहले देखी गई जगह की जानकारी देती है जिससे पिक्सल कॉपी किए जाते हैं. सटीक मैपिंग है इसके बारे में नीचे बताया गया है.

लंबाई और दूरी की वैल्यू, LZ77 प्रीफ़िक्स कोडिंग का इस्तेमाल करके सेव की जाती हैं.

LZ77 प्रीफ़िक्स कोडिंग, बड़े पूर्णांक वैल्यू को दो हिस्सों में बांटती है: प्रीफ़िक्स कोड कोड और अतिरिक्त बिट. प्रीफ़िक्स कोड को एन्ट्रॉपी कोड का इस्तेमाल करके स्टोर किया जाता है, जबकि अतिरिक्त बिट उसी रूप में सेव किए जाते हैं, जैसे कि (एंट्रॉपी कोड के बिना).

तकरीबन: इस तरीके से एंट्रॉपी के लिए स्टोरेज की ज़रूरत कम हो जाती है कोड. साथ ही, बड़े मान आम तौर पर बहुत कम होते हैं, इसलिए अतिरिक्त बिट का इस्तेमाल इमेज में कुछ वैल्यू हैं. इस तरह, इस तरीके की वजह से कंप्रेशन बेहतर होता है कुल मिलाकर.

नीचे दी गई टेबल में प्रीफ़िक्स कोड और स्टोर करने के लिए इस्तेमाल किए जाने वाले अतिरिक्त बिट के बारे में बताया गया है डालें.

मान की सीमा प्रीफ़िक्स कोड अतिरिक्त बिट
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

प्रीफ़िक्स कोड से (लंबाई या दूरी) का मान पाने के लिए स्यूडोकोड इस तरह से है अनुसरण करता है:

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;
दूरी को मैप करना

जैसा कि पहले ही बताया जा चुका है, दूरी का कोड वह संख्या होती है जो किसी पहले देखे गए पिक्सल, जिससे पिक्सल कॉपी किए जाने हैं. यह सब-सेक्शन दूरी के कोड और पिछले सवाल की जगह के बीच की मैपिंग को तय करता है Pixel है.

दूरी के कोड 120 से ज़्यादा होने पर, स्कैन-लाइन के क्रम में पिक्सल की दूरी पता चलती है. 120 तक ऑफ़सेट कर देता है.

सबसे छोटी दूरी के कोड [1..120] खास होते हैं और इन्हें क्लोज़िंग मौजूदा Pixel के आस-पास की जगह पर होना चाहिए. इस आस-पड़ोस में 120 पिक्सेल शामिल हैं:

  • ऐसे पिक्सल जो मौजूदा पिक्सल से एक से सात लाइन ऊपर और आठ कॉलम तक हो सकते हैं मौजूदा पिक्सल के बाएं या ज़्यादा से ज़्यादा सात कॉलम दाईं ओर. [कुल योग ऐसे पिक्सल = 7 * (8 + 1 + 7) = 112].
  • ऐसे पिक्सल जो उसी लाइन में हों जिसमें मौजूदा पिक्सल मौजूद है और जिसकी लंबाई आठ से ज़्यादा नहीं हो सकती कॉलम पर क्लिक करें. [8 ऐसे पिक्सल].

दूरी के कोड distance_code और आस-पास के पिक्सल के बीच की मैपिंग ऑफ़सेट (xi, yi) इस तरह है:

(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)

उदाहरण के लिए, दूरी कोड 1(0, 1) आस-पास मौजूद पिक्सल, यानी मौजूदा पिक्सल (0 पिक्सल) से ज़्यादा पिक्सल X दिशा में और Y दिशा में 1 पिक्सल का अंतर). इसी तरह, दूरी का कोड 3 ऊपर बाएं पिक्सल को दिखाता है.

डिकोडर, दूरी के कोड distance_code को स्कैन लाइन के क्रम में बदल सकता है दूरी dist इस प्रकार है:

(xi, yi) = distance_map[distance_code - 1]
dist = xi + yi * image_width
if (dist < 1) {
  dist = 1
}

जहां distance_map ऊपर बताई गई मैपिंग है और image_width चौड़ाई है पिक्सल में बदलें.

5.2.3 कलर कैश कोडिंग

कलर कैश मेमोरी उन रंगों का सेट सेव करती है जिन्हें हाल ही में इमेज में इस्तेमाल किया गया है.

तर्क: इस तरह, हाल ही में इस्तेमाल किए गए रंगों को कभी-कभी कार्बन उत्सर्जन को कम करने के लिए, 5.2.1 और 5.2.2).

कलर कैश कोड इस तरह सेव किए जाते हैं. सबसे पहले, एक 1-बिट मान होता है, यह बताता है कि कलर कैश मेमोरी का इस्तेमाल किया गया है या नहीं. अगर यह बिट 0 है, तो कलर कैश कोड को कोई कलर नहीं किया जाएगा मौजूद हैं और उन्हें प्रीफ़िक्स कोड में ट्रांसमिट नहीं किया जाता, जो हरे रंग को डीकोड करता है और लंबे प्रीफ़िक्स कोड शामिल करें. हालांकि, अगर यह बिट 1 है, तो कलर कैश इसके बाद साइज़ की जानकारी पढ़ें:

int color_cache_code_bits = ReadBits(4);
int color_cache_size = 1 << color_cache_code_bits;

color_cache_code_bits, कलर कैश (1 << color_cache_code_bits) का साइज़ बताता है. वैल्यू की वह रेंज जिसका इस्तेमाल करने की अनुमति है color_cache_code_bits [1..11] है. अनुपालन करने वाले डिकोडर को यह बताना चाहिए कि अन्य वैल्यू के लिए करप्ट बिटस्ट्रीम.

कलर कैश, color_cache_size साइज़ का कलेक्शन होता है. हर एंट्री में एक ARGB सेव होता है रंग. रंगों को (0x1e35a7bd * color) >> (32 - color_cache_code_bits) से इंडेक्स करके, उनकी जांच की जाती है. कलर कैश में सिर्फ़ एक लुकअप किया जाता है; नहीं है विवाद का हल.

किसी इमेज को डिकोड करने या कोड में बदलने की शुरुआत में, सभी एंट्री सभी रंगों में कैश मेमोरी का मान शून्य पर सेट होता है. रंग कैश कोड को इस रंग में बदला जाता है डिकोड करने में लगने वाला समय. कलर कैश की स्थिति को बनाए रखने के लिए, नहीं किया जा सकता, फिर चाहे वह बैकवर्ड रेफ़रंस या लिटरल रूप में हो, वे स्ट्रीम में किस क्रम में दिखते हैं.

6 एन्ट्रॉपी कोड

6.1 खास जानकारी

ज़्यादातर डेटा को कैननिकल प्रीफ़िक्स कोड का इस्तेमाल करके कोड किया जाता है. इसलिए, प्रीफ़िक्स कोड की लंबाई भेजकर कोड इस तरह से भेजे जाते हैं यह असली प्रीफ़िक्स कोड के उलट है.

खास तौर पर, फ़ॉर्मैट में स्पेशल वैरिएंट प्रीफ़िक्स कोडिंग का इस्तेमाल किया जाता है. अन्य शब्द, इमेज के अलग-अलग ब्लॉक अलग-अलग एन्ट्रॉपी का इस्तेमाल कर सकते हैं कोड.

तथ्यों के हिसाब से: इमेज के अलग-अलग हिस्सों की विशेषताएं अलग-अलग हो सकती हैं. इसलिए, उन्हें अलग-अलग एंट्रॉपी कोड का इस्तेमाल करने की अनुमति देने से, ज़्यादा सुविधा मिलती है और बेहतर संपीड़न हो सकता है.

6.2 जानकारी

कोड में बदले गए इमेज के डेटा के कई हिस्से होते हैं:

  1. प्रीफ़िक्स कोड डिकोड करना और बनाना.
  2. मेटा प्रीफ़िक्स कोड.
  3. एंट्रॉपी कोड किया गया इमेज डेटा.

किसी भी दिए गए पिक्सल (x, y) के लिए पांच प्रीफ़िक्स कोड का सेट होता है इसे. ये कोड हैं (बिटस्ट्रीम क्रम में):

  • प्रीफ़िक्स कोड #1: इसका इस्तेमाल ग्रीन चैनल, बैकवर्ड रेफ़रंस की लंबाई, और कलर कैश.
  • प्रीफ़िक्स कोड #2, #3, और #4: लाल, नीले, और ऐल्फ़ा चैनलों के लिए इस्तेमाल किया जाता है, क्रम से.
  • प्रीफ़िक्स कोड #5: इसका इस्तेमाल बैकवर्ड-रेफ़रंस दूरी के लिए किया जाता है.

आगे से, हम इस सेट को प्रीफ़िक्स कोड ग्रुप के तौर पर देखते हैं.

6.2.1 प्रीफ़िक्स कोड बनाना और डिकोड करना

इस सेक्शन में बिटस्ट्रीम से प्रीफ़िक्स कोड की लंबाई को पढ़ने का तरीका बताया गया है.

प्रीफ़िक्स कोड की लंबाई को दो तरह से कोड किया जा सकता है. इस्तेमाल किया गया तरीका बताया गया हो को 1-बिट वैल्यू से गुणा कर सकते हैं.

  • अगर यह बिट 1 है, तो यह आसान कोड लंबाई वाला कोड है.
  • अगर यह बिट 0 है, तो यह कोड की लंबाई का सामान्य कोड है.

दोनों मामलों में, इस्तेमाल न होने वाले ऐसे कोड हो सकते हैं जो अब भी इस एट्रिब्यूट का हिस्सा हैं स्ट्रीम. ऐसा हो सकता है कि ऐसा करना ठीक न हो, लेकिन फ़ॉर्मैट के हिसाब से ऐसा किया जा सकता है. बताया गया ट्री एक पूरा बाइनरी ट्री होना चाहिए. एक लीफ़ नोड एक पूर्ण बाइनरी ट्री माना जाता है और इसे सरल कोड की लंबाई का कोड या सामान्य कोड लंबाई वाला कोड. एक पत्ती की कोडिंग करते समय नोड में सामान्य कोड लंबाई के कोड का इस्तेमाल किया जाता है, लेकिन एक कोड लंबाई को छोड़कर बाकी सभी शून्य होते हैं. और सिंगल लीफ़ नोड वैल्यू को 1 की लंबाई से मार्क किया जाता है -- भले ही कोई नहीं बिट तब इस्तेमाल किए जाते हैं, जब उस सिंगल लीफ़ नोड ट्री का इस्तेमाल किया जाता है.

सरल कोड लंबाई का कोड

इस वैरिएंट का इस्तेमाल खास मामले में तब किया जाता है, जब प्रीफ़िक्स के तौर पर सिर्फ़ एक या दो सिंबल इस्तेमाल किए गए हों 1 कोड की लंबाई के साथ [0..255] रेंज. अन्य सभी प्रीफ़िक्स कोड की लंबाई यह है इंप्लिसिट तौर पर शून्य.

पहला बिट सिंबल की संख्या दिखाता है:

int num_symbols = ReadBits(1) + 1;

ये रहे सिंबल की वैल्यू.

यह पहला प्रतीक 1 या 8 बिट का उपयोग करके कोड किया जाता है, जो is_first_8bits. यह रेंज [0..1] या [0..255] है. दूसरा चिह्न मौजूद होने पर यह हमेशा [0..255] की रेंज में होता है और कोड में होता है 8 बिट का इस्तेमाल करके.

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;
}

दोनों चिह्न अलग-अलग होने चाहिए. डुप्लीकेट चिह्नों की अनुमति है, लेकिन कम प्रभावी थे.

ध्यान दें: एक और खास मामला यह है कि प्रीफ़िक्स कोड के सभी वर्णों की लंबाई शून्य होनी चाहिए ( खाली प्रीफ़िक्स कोड शामिल होना चाहिए). उदाहरण के लिए, दूरी के लिए प्रीफ़िक्स कोड खाली हो सकता है, अगर पीछे कोई रेफ़रंस नहीं है. इसी तरह, अल्फ़ा, लाल और अगर एक ही मेटा प्रीफ़िक्स कोड में सभी पिक्सल बनाए जाते हैं, तो नीला हो सकता है कलर कैश का इस्तेमाल करके. हालांकि, इस मामले को किसी खास तरीके से इस्तेमाल करने की ज़रूरत नहीं है, क्योंकि खाली प्रीफ़िक्स कोड को कोड में बदला जा सकता है, क्योंकि इनमें एक चिह्न 0 होता है.

सामान्य कोड लंबाई कोड

प्रीफ़िक्स कोड के कोड की लंबाई आठ बिट में होती है और इसे इस तरह से पढ़ा जाता है. सबसे पहले, num_code_lengths, कोड की लंबाई की संख्या बताता है.

int num_code_lengths = 4 + ReadBits(4);

कोड की लंबाई को प्रीफ़िक्स कोड का इस्तेमाल करके एन्कोड किया जाता है; लोअर-लेवल कोड लंबाई, code_length_code_lengths, पहले पढ़ना होगा. बाकी के code_length_code_lengths (kCodeLengthCodeOrder में दिए गए ऑर्डर के मुताबिक) शून्य हैं.

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);
}

इसके बाद, अगर ReadBits(1) == 0 है, तो पढ़े जाने वाले अलग-अलग सिंबल की ज़्यादा से ज़्यादा संख्या हर सिंबल टाइप (A, R, G, B, और दूरी) के लिए (max_symbol) को वर्णमाला का आकार:

  • G चैनल: 256 + 24 + color_cache_size
  • अन्य लिटरल (A, R, और B): 256
  • दूरी का कोड: 40

नहीं तो, इसे इस तरह से परिभाषित किया गया है:

int length_nbits = 2 + 2 * ReadBits(3);
int max_symbol = 2 + ReadBits(length_nbits);

अगर max_symbol, सिंबल टाइप के लिए अक्षरों के साइज़ से बड़ा है, तो बिटस्ट्रीम अमान्य है.

इसके बाद, code_length_code_lengths से एक प्रीफ़िक्स टेबल बनाई जाती है. इसका इस्तेमाल, पढ़ने के लिए किया जाता है लंबाई max_symbol तक.

  • कोड [0..15], लिटरल कोड की लंबाई के बारे में बताता है.
    • वैल्यू 0 का मतलब है कि किसी भी सिंबल को कोड नहीं किया गया है.
    • वैल्यू [1..15], उनसे जुड़े कोड की बिट की लंबाई दिखाती हैं.
  • कोड 16 पिछली नॉन-ज़ीरो वैल्यू को [3..6] बार दोहराता है, इसका मतलब है कि 3 + ReadBits(2) बार. अगर कोड 16 का इस्तेमाल शून्य से पहले किया जाता है वैल्यू दी गई है, लेकिन 8 वैल्यू दोहराई गई है.
  • कोड 17 के नतीजे में कई शून्य [3..10] हैं, यानी कि 3 + ReadBits(3) बार.
  • कोड 18 में शून्यों की एक स्ट्रीक निकलती है [11..138], इसका मतलब है कि 11 + ReadBits(7) बार.

कोड की लंबाई पढ़ने के बाद, हर सिंबल टाइप (A, R, G, B, और दूरी) का चुनाव उनके वर्णमाला के आकार का इस्तेमाल करके किया जाता है.

सामान्य कोड लंबाई कोड में एक पूरे डिसिज़न ट्री को कोड किया जाना चाहिए, यानी कि शून्य के अलावा सभी कोड के लिए 2 ^ (-length) एक होना चाहिए. हालांकि, यहां इस नियम का एक अपवाद, सिंगल लीफ़ नोड ट्री, जहां लीफ़ नोड वैल्यू को 1 और अन्य वैल्यू 0 से मार्क की गई है.

6.2.2 मेटा प्रीफ़िक्स कोड की डिकोडिंग

जैसा कि पहले बताया गया है, इस फ़ॉर्मैट में यूआरएल के लिए अलग-अलग प्रीफ़िक्स कोड इस्तेमाल किए जा सकते हैं ब्लॉक कर दिया जाता है. मेटा प्रीफ़िक्स कोड ऐसे इंडेक्स होते हैं जिनसे पता चलता है कि का इस्तेमाल करें.

मेटा प्रीफ़िक्स कोड का इस्तेमाल सिर्फ़ तब किया जा सकता है, जब इमेज का इस्तेमाल ARGB इमेज की भूमिका.

1-बिट की मदद से, मेटा प्रीफ़िक्स कोड इस्तेमाल करने की दो वजहें होती हैं मान:

  • अगर यह बिट शून्य है, तो हर जगह सिर्फ़ एक मेटा प्रीफ़िक्स कोड का इस्तेमाल किया जाएगा इमेज को हाइलाइट करें. कोई और डेटा सेव नहीं किया जाता.
  • अगर यह बिट एक है, तो इमेज में एक से ज़्यादा मेटा प्रीफ़िक्स कोड इस्तेमाल किए गए हैं. ये मेटा प्रीफ़िक्स कोड एंट्रॉपी इमेज के तौर पर सेव किए जाते हैं. इस बारे में नीचे बताया गया है.

पिक्सल के लाल और हरे रंग के कॉम्पोनेंट, 16-बिट वाला मेटा प्रीफ़िक्स कोड तय करते हैं ARGB इमेज का कोई खास ब्लॉक.

एंट्रॉपी इमेज

एंट्रॉपी इमेज से यह तय होता है कि इमेज.

पहले 3 बिट में prefix_bits वैल्यू होती है. एंट्रॉपी के डाइमेंशन इमेज prefix_bits से ली गई है:

int prefix_bits = ReadBits(3) + 2;
int prefix_image_width =
    DIV_ROUND_UP(image_width, 1 << prefix_bits);
int prefix_image_height =
    DIV_ROUND_UP(image_height, 1 << prefix_bits);

जहां DIV_ROUND_UP को पहले के तौर पर परिभाषित किया गया है.

अगले बिट में चौड़ाई prefix_image_width और ऊंचाई की एक एंट्रॉपी इमेज होती है prefix_image_height.

मेटा प्रीफ़िक्स कोड की व्याख्या

ARGB इमेज में प्रीफ़िक्स कोड ग्रुप की संख्या एन्ट्रॉपी इमेज से मिला सबसे बड़ा मेटा प्रीफ़िक्स कोड:

int num_prefix_groups = max(entropy image) + 1;

जहां max(entropy image) एन्ट्रॉपी इमेज.

हर प्रीफ़िक्स कोड ग्रुप में पांच प्रीफ़िक्स कोड होते हैं. इसलिए, प्रीफ़िक्स की कुल संख्या कोड है:

int num_prefix_codes = 5 * num_prefix_groups;

ARGB इमेज में पिक्सल (x, y) दिए जाने पर, हम संबंधित प्रीफ़िक्स का पता कर सकते हैं कोड को इस तरह से इस्तेमाल करें:

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 संरचना की मौजूदगी का अनुमान लगाया है, पांच प्रीफ़िक्स कोड के सेट को दिखाता है. साथ ही, prefix_code_groups PrefixCodeGroup (साइज़ num_prefix_groups का).

इसके बाद, डिकोडर पिक्सल को डिकोड करने के लिए प्रीफ़िक्स कोड ग्रुप prefix_group का इस्तेमाल करता है (x, y), जैसा कि "डिकोडिंग एंट्रॉपी-कोडेड इमेज" में बताया गया है डेटा".

6.2.3 डिकोडिंग एंट्रॉपी-कोडेड इमेज डेटा

इमेज की मौजूदा पोज़िशन (x, y) के लिए डिकोडर सबसे पहले, संबंधित प्रीफ़िक्स कोड ग्रुप (जैसा कि पिछले सेक्शन में बताया गया है). यह देखते हुए प्रीफ़िक्स कोड ग्रुप के आधार पर तय किया गया है, तो पिक्सल को इस तरह पढ़ा और डिकोड किया जाता है.

इसके बाद, बिटस्ट्रीम से प्रीफ़िक्स कोड #1 का इस्तेमाल करके, S सिंबल पढ़ें. ध्यान दें कि S का मतलब 0 से तक की रेंज में कोई भी पूर्णांक (256 + 24 + color_cache_size- 1).

S का मतलब, इसकी वैल्यू पर निर्भर करता है:

  1. यदि S < 256
    1. हरे रंग के कॉम्पोनेंट के तौर पर, S का इस्तेमाल करें.
    2. प्रीफ़िक्स कोड #2 का इस्तेमाल करके, बिटस्ट्रीम से लाल रंग के टेक्स्ट को पढ़ें.
    3. प्रीफ़िक्स कोड #3 का इस्तेमाल करके, बिटस्ट्रीम से नीले रंग को पढ़ें.
    4. प्रीफ़िक्स कोड #4 का इस्तेमाल करके, बिटस्ट्रीम से ऐल्फ़ा पढ़ें.
  2. अगर S >= 256 और शनि < 256 + 24 साल
    1. लंबाई के प्रीफ़िक्स कोड के तौर पर, S - 256 का इस्तेमाल करें.
    2. बिटस्ट्रीम से लंबाई के लिए अतिरिक्त बिट पढ़ें.
    3. लंबाई उपसर्ग कोड से पीछे-संदर्भ की लंबाई L और अतिरिक्त बिट पढ़ें.
    4. प्रीफ़िक्स कोड #5 का इस्तेमाल करके, बिटस्ट्रीम से दूरी का प्रीफ़िक्स कोड पढ़ें.
    5. बिटस्ट्रीम से दूरी के लिए अतिरिक्त बिट पढ़ें.
    6. दूरी उपसर्ग कोड से पीछे-संदर्भ की दूरी D ज्ञात करें और अतिरिक्त बिट पढ़े जा सकते हैं.
    7. शुरू होने वाले पिक्सेल के क्रम से L पिक्सेल (स्कैन-लाइन के क्रम में) कॉपी करें D पिक्सल को घटाकर मौजूदा पोज़िशन पर.
  3. अगर S >= 256 + 24 है
    1. कलर कैश में इंडेक्स के तौर पर S - (256 + 24) का इस्तेमाल करें.
    2. उस इंडेक्स में कलर कैश से ARGB रंग पाएं.

7 फ़ॉर्मैट का पूरा स्ट्रक्चर

यहां ऑगमेंटेड बैकस-नौर फ़ॉर्म (एबीएनएफ़) का फ़ॉर्मैट दिखाया गया है आरएफ़सी 5234 आरएफ़सी 7405. इसमें पूरी जानकारी नहीं है. इमेज खत्म होने की तारीख (ईओआई) इसे सिर्फ़ पिक्सल की संख्या (image_width * image_height) में इंप्लिसिट रूप से कोड किया गया है.

ध्यान दें कि *element का मतलब है कि element को 0 या उससे ज़्यादा बार दोहराया जा सकता है. 5element अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है इसका मतलब है कि element को सिर्फ़ पांच बार दोहराया गया है. %b, बाइनरी वैल्यू दिखाता है.

7.1 बुनियादी स्ट्रक्चर

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 बदलाव की संरचना

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 इमेज डेटा का स्ट्रक्चर

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)

नीचे उदाहरण के तौर पर एक क्रम दिया गया है:

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