जरकी अलाकुइजाला, पीएच॰डी॰, 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 इमेज
- दो डाइमेंशन वाला अरे, जिसमें ARGB पिक्सल मौजूद हों.
- कलर कैश
- हाल ही में इस्तेमाल किए गए रंगों को स्टोर करने के लिए, हैश के आधार पर तैयार किया गया छोटा अरे. उन्हें छोटे कोड से याद करते हैं.
- कलर इंडेक्स करने वाली इमेज
- रंगों की एक डाइमेंशन वाली इमेज, जिसे छोटे पूर्णांक का इस्तेमाल करके इंडेक्स किया जा सकता है (WebP लॉसलेस में 256 तक).
- रंग बदलने वाली इमेज
- दो-डाइमेंशन वाली सबरिज़ॉल्यूशन वाली इमेज, जिसमें रंग कॉम्पोनेंट.
- दूरी की मैपिंग
- पिक्सल के लिए सबसे छोटी वैल्यू रखने के लिए, LZ77 दूरी को बदलता है दो डाइमेंशन में आस-पास की जगह हो.
- एन्ट्रॉपी इमेज
- दो-डाइमेंशन वाली सबरिज़ॉल्यूशन वाली इमेज, जिससे पता चलता है कि किस एंट्रॉपी कोडिंग को करना चाहिए इसे इमेज में संबंधित वर्ग में इस्तेमाल किया जाना चाहिए, यानी हर पिक्सेल एक मेटा प्रीफ़िक्स कोड होना चाहिए.
- LZ77
- शब्दकोश पर आधारित स्लाइडिंग विंडो कंप्रेशन एल्गोरिदम, जो या तो उत्सर्जन करता है निशान या उन्हें पुराने प्रतीकों के क्रम के तौर पर पेश करता है.
- मेटा प्रीफ़िक्स कोड
- एक छोटा पूर्णांक (ज़्यादा से ज़्यादा 16 बिट), जो मेटा प्रीफ़िक्स में किसी एलिमेंट को इंडेक्स करता हो टेबल.
- अनुमान लगाने वाली इमेज
- दो-डाइमेंशन वाली सबरिज़ॉल्यूशन वाली इमेज, जो बताती है कि जगह की जानकारी का अनुमान कौनसा है का इस्तेमाल इमेज में किसी स्क्वेयर स्क्वेयर के लिए किया गया हो.
- उपसर्ग कोड
- एंट्रॉपी कोडिंग करने का एक क्लासिक तरीका, जिसमें कम बिट का इस्तेमाल किया जाता है अक्सर इस्तेमाल किए जाने वाले कोड के लिए.
- प्रीफ़िक्स कोडिंग
- बड़े पूर्णांकों को एंट्रॉपी करने का तरीका, जो पूर्णांक के कुछ बिट को कोड करते हैं एंट्रॉपी कोड का इस्तेमाल करके और बची हुई बिट को कोड करता है. इससे आपको हालांकि, एंट्रॉपी कोड की तुलना में छोटे एलिमेंट को मिलाकर बनाए गए में चिह्नों की रेंज बड़ी हो.
- स्कैन-लाइन का क्रम
- पिक्सल का प्रोसेसिंग ऑर्डर (बाएं से दाएं और ऊपर से नीचे), शुरू होता है ऊपर की ओर तीर के निशान से. पंक्ति पूरी होने के बाद, यहां से जारी रखें अगली पंक्ति के बाईं ओर मौजूद कॉलम पर क्लिक करें.
3 RIFF हेडर
हेडर की शुरुआत में RIFF कंटेनर होता है. इसमें यह शामिल है ये 21 बाइट होने चाहिए:
- स्ट्रिंग 'RIFF'.
- चंक की लंबाई की 32-बिट वैल्यू, जो कि RIFF हेडर से कंट्रोल किए जाने वाले चंक का पूरा साइज़ है. आम तौर पर, यह इसके बराबर होता है पेलोड का साइज़ (फ़ाइल का साइज़ 8 बाइट से कम: 'RIFF' के लिए 4 बाइट आइडेंटिफ़ायर और वैल्यू को स्टोर करने के लिए 4 बाइट).
- स्ट्रिंग 'WEBP' (RIFF कंटेनर का नाम).
- स्ट्रिंग 'VP8L' (लॉसलेस-एन्कोडेड इमेज डेटा के लिए चारसीसी).
- लिटिल-एंडियन, 32-बिट की वैल्यू स्ट्रीम न करें.
- 1-बाइट का सिग्नेचर 0x2f.
बिटस्ट्रीम के पहले 28 बिट से, इमेज की चौड़ाई और ऊंचाई का पता चलता है. चौड़ाई और ऊंचाई को 14-बिट पूर्णांक के तौर पर इस तरह डिकोड किया जाता है:
int image_width = ReadBits(14) + 1;
int image_height = ReadBits(14) + 1;
इमेज की चौड़ाई और ऊंचाई के लिए 14-बिट सटीक होने से, इमेज की ज़्यादा से ज़्यादा साइज़ WebP वाली लॉसलेस इमेज, जिसका साइज़ 16384 गुना16384 पिक्सल है.
alpha_is_used बिट सिर्फ़ एक हिंट है. इससे डिकोडिंग पर कोई असर नहीं पड़ना चाहिए. इसे ऐसा होना चाहिए जब चित्र में सभी अल्फ़ा मान 255 हों, तो 0 पर सेट हो, और नहीं तो 1 पर सेट हो.
int alpha_is_used = ReadBits(1);
version_number 3 बिट का कोड है, जिसे 0 पर सेट करना ज़रूरी है. किसी भी दूसरी वैल्यू को गड़बड़ी माना जाना चाहिए.
int version_number = ReadBits(3);
चार ट्रांसफ़ॉर्म
ट्रांसफ़ॉर्मेशन, इमेज डेटा में बदलाव करने की ऐसी प्रोसेस है जिसे वापस लाया जा सकता है. इससे स्पेस और कलर के बीच के संबंधों को मॉडलिंग करके, बाकी बचा सिंबल एन्ट्रोपी कम किया जा सकता है. वे अंतिम संपीड़न को और घना बना सकते हैं.
एक इमेज में चार तरह के बदलाव हो सकते हैं. 1 बिट का मतलब बदलाव की मौजूदगी. हर ट्रांसफ़ॉर्म को सिर्फ़ एक बार इस्तेमाल किया जा सकता है. ट्रांसफ़ॉर्म का इस्तेमाल सिर्फ़ मुख्य लेवल की ARGB इमेज के लिए किया जाता है. सब-रिज़ॉल्यूशन इमेज (रंग ट्रांसफ़ॉर्म इमेज, एन्ट्रापी इमेज, और प्रिडिक्टर इमेज) में कोई ट्रांसफ़ॉर्म नहीं होता. यहां तक कि ट्रांसफ़ॉर्म के खत्म होने का संकेत देने वाला 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 अनुमान लगाने वाला बदलाव
एंट्रॉपी को कम करने के लिए, तथ्य का गलत इस्तेमाल करके अनुमान लगाने वाले ट्रांसफ़ॉर्म का इस्तेमाल किया जा सकता है आस-पास के पिक्सल अक्सर एक-दूसरे से जुड़े होते हैं. अनुमान लगाने वाले के बदलाव में, मौजूदा पिक्सल की वैल्यू का अनुमान, पहले से डिकोड किए गए पिक्सल (स्कैन-लाइन में) से लगाया जाता है क्रम) और सिर्फ़ रेज़िड्यूअल वैल्यू (असल - अनुमानित) को कोड में बदला जाता है. पिक्सल के हरे रंग के घटक से यह तय होता है कि ARGB इमेज के किसी खास ब्लॉक में, 14 में से किस अनुमान लगाने वाले एल्गोरिदम का इस्तेमाल किया जाए. पूर्वानुमान मोड इस्तेमाल करने के लिए सुझाव. हम इमेज को स्क्वेयर में बांटते हैं और स्क्वेयर के सभी पिक्सल, एक ही अनुमान मोड का इस्तेमाल करते हैं.
अनुमान के डेटा के पहले तीन बिट, संख्या में ब्लॉक की चौड़ाई और ऊंचाई तय करते हैं बिट में से.
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 | Average2(Average2(L, TR), T) |
6 | Average2(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-बिट के साथ) का इस्तेमाल करके किया जाना है प्रिसिज़न). शिफ़्ट कार्रवाई की साइन एक्सटेंशन प्रॉपर्टी इससे कोई फ़र्क़ नहीं पड़ता यहां; नतीजे से सिर्फ़ सबसे नीचे के आठ बिट का इस्तेमाल किया जाता है. साथ ही, इन बिट में साइन एक्सटेंशन शिफ़्टिंग और बिना साइन इन किए हुए शिफ़्टिंग का तरीका एक-दूसरे से मेल खाता है.
अब हम कलर ट्रांसफ़ॉर्म डेटा के कॉन्टेंट के बारे में बताते हैं, ताकि डिकोडिंग में इनवर्स कलर ट्रांसफ़ॉर्म लागू किया जा सके और मूल लाल और नीली वैल्यू वापस पाई जा सकें. कॉन्टेंट बनाने कलर ट्रांसफ़ॉर्म डेटा के पहले तीन बिट में, जैसे कि अनुमान लगाने वाले के बदलाव की तरह इमेज ब्लॉक में बिट की संख्या:
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 ≡ 0 (mod 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 इमेज डेटा की भूमिकाएं
हम इमेज डेटा का इस्तेमाल पांच अलग-अलग तरीकों से करते हैं:
- ARGB इमेज: इमेज के असल पिक्सल को सेव करती है.
- एंट्रॉपी इमेज: मेटा प्रीफ़िक्स कोड स्टोर करती है (देखें "मेटा प्रीफ़िक्स कोड की डिकोडिंग").
- अनुमान लगाने वाले की इमेज: अनुमान लगाने वाले के बदलाव के मेटाडेटा को स्टोर करती है (देखें "प्रेडिक्टर ट्रांसफ़ॉर्म").
- रंग बदलने वाली इमेज:
ColorTransformElement
वैल्यू से बनाया गया अलग-अलग ब्लॉक के लिए ("कलर ट्रांसफ़ॉर्म" में बताया गया है) पर क्लिक करें. - कलर इंडेक्स करने वाली इमेज:
color_table_size
के साइज़ का कलेक्शन (256 तक) ARGB मान) जो रंग सूची में बदलाव के लिए मेटाडेटा को स्टोर करता है (देखें "कलर इंडेक्स करने का तरीका बदलना").
5.2 इमेज डेटा की एन्कोडिंग
इमेज डेटा को कोड में बदलने का तरीका, उसकी भूमिका से अलग होता है.
इमेज को पहले, तय साइज़ के ब्लॉक (आम तौर पर 16x16) में बांटा जाता है ब्लॉक). इनमें से हर ब्लॉक को उसके एन्ट्रापी कोड का इस्तेमाल करके बनाया जाता है. साथ ही, कई ब्लॉक एक ही एंट्रॉपी कोड शेयर कर सकते हैं.
रायलाय: किसी एंट्रॉपी कोड को स्टोर करने के लिए शुल्क देना पड़ता है. इस लागत को कम किया जा सकता है अगर आंकड़ों के हिसाब से मिलते-जुलते ब्लॉक एक एंट्रॉपी कोड शेयर करते हैं, तो उस कोड को सेव किया जाता है का इस्तेमाल करें. उदाहरण के लिए, एन्कोडर एक जैसे ब्लॉक को क्लस्टर में बांटकर उन्हें ढूंढ सकता है या यादृच्छिक रूप से जोड़े जाने के लिए बार-बार क्लस्टर तब चुने जाते हैं, जब यह कोड में बदलने के लिए ज़रूरी बिट की कुल संख्या को कम करता है इमेज.
हर पिक्सल को कोड में बदलने के लिए, तीन संभावित तरीकों में से किसी एक का इस्तेमाल किया जाता है:
- प्रीफ़िक्स कोड वाली लिटरल वैल्यू: हर चैनल (हरा, लाल, नीला, और ऐल्फ़ा) अलग से कोड में बदला गया हो.
- LZ77 बैकवर्ड रेफ़रंस: पिक्सल का सीक्वेंस, इसमें कहीं और से कॉपी किया जाता है इमेज.
- कलर कैश कोड: एक छोटे मल्टीप्लिकेटिव हैश कोड (कलर कैश) का इस्तेमाल करना इंडेक्स).
इन सब-सेक्शन में, इनके बारे में पूरी जानकारी दी गई है.
5.2.1 प्रीफ़िक्स-कोडेड लिटरल
पिक्सल को हरे, लाल, नीले, और अल्फा के प्रीफ़िक्स-कोड वाली वैल्यू के तौर पर सेव किया जाता है. इनके लिए सेक्शन 6.2.3 देखें विवरण.
5.2.2 LZ77 बैकवर्ड रेफ़रंस
बैकवर्ड रेफ़रंस, लंबाई और डिस्टेंस कोड के टपल होते हैं:
- लंबाई से पता चलता है कि स्कैन-लाइन के क्रम में कितने पिक्सल कॉपी किए जाने हैं.
- दूरी का कोड वह संख्या है जो पहले देखी गई जगह की जानकारी देती है जिससे पिक्सल कॉपी किए जाते हैं. सटीक मैपिंग है इसके बारे में नीचे बताया गया है.
लंबाई और दूरी की वैल्यू, 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 जानकारी
कोड में बदले गए इमेज के डेटा के कई हिस्से होते हैं:
- प्रीफ़िक्स कोड डिकोड करना और बनाना.
- मेटा प्रीफ़िक्स कोड.
- एंट्रॉपी कोड किया गया इमेज डेटा.
किसी भी दिए गए पिक्सल (x, y) के लिए पांच प्रीफ़िक्स कोड का सेट होता है इसे. ये कोड हैं (बिटस्ट्रीम क्रम में):
- प्रीफ़िक्स कोड #1: इसका इस्तेमाल ग्रीन चैनल, बैकवर्ड-रेफ़रंस की लंबाई, और रंग कैश मेमोरी के लिए किया जाता है.
- प्रीफ़िक्स कोड #2, #3, और #4: लाल, नीले, और ऐल्फ़ा चैनलों के लिए इस्तेमाल किया जाता है, क्रम से.
- प्रीफ़िक्स कोड #5: इसका इस्तेमाल बैकवर्ड-रेफ़रंस दूरी के लिए किया जाता है.
आगे से, हम इस सेट को प्रीफ़िक्स कोड ग्रुप के तौर पर देखते हैं.
6.2.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 की वैल्यू के आधार पर, इसका मतलब अलग-अलग होता है:
- यदि S < 256
- हरे रंग के कॉम्पोनेंट के तौर पर, S का इस्तेमाल करें.
- प्रीफ़िक्स कोड #2 का इस्तेमाल करके, बिटस्ट्रीम से लाल रंग के टेक्स्ट को पढ़ें.
- प्रीफ़िक्स कोड #3 का इस्तेमाल करके, बिटस्ट्रीम से नीले रंग को पढ़ें.
- प्रीफ़िक्स कोड #4 का इस्तेमाल करके, बिटस्ट्रीम से ऐल्फ़ा पढ़ें.
- अगर S >= 256 और शनि < 256 + 24 साल
- लंबाई के प्रीफ़िक्स कोड के तौर पर, S - 256 का इस्तेमाल करें.
- बिटस्ट्रीम से लंबाई के लिए अतिरिक्त बिट पढ़ें.
- लंबाई के प्रीफ़िक्स कोड और पढ़े गए अतिरिक्त बिट से, बैकवर्ड-रेफ़रंस की लंबाई L का पता लगाएं.
- प्रीफ़िक्स कोड #5 का इस्तेमाल करके, बिटस्ट्रीम से दूरी का प्रीफ़िक्स कोड पढ़ें.
- बिटस्ट्रीम से दूरी के लिए अतिरिक्त बिट पढ़ें.
- दूरी उपसर्ग कोड से पीछे-संदर्भ की दूरी D ज्ञात करें और अतिरिक्त बिट पढ़े जा सकते हैं.
- शुरू होने वाले पिक्सेल के क्रम से L पिक्सेल (स्कैन-लाइन के क्रम में) कॉपी करें D पिक्सल को घटाकर मौजूदा पोज़िशन पर.
- अगर S >= 256 + 24 है
- कलर कैश में इंडेक्स के तौर पर S - (256 + 24) का इस्तेमाल करें.
- उस इंडेक्स में कलर कैश से 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