"جيركي ألاكويجالا"، دكتوراه Google, Inc., 2023-03-09
ملخص
تنسيق WebP بدون فقدان البيانات هو تنسيق صور لضغط الصور بتنسيق ARGB بدون فقدان البيانات. يخزِّن التنسيق غير القابل للفقدان قيم البكسل ويعيدها بدقة، بما في ذلك قيم الألوان لوحدات البكسل الشفافة بالكامل. يتم استخدام خوارزمية عالمية لضغط البيانات التسلسلي (LZ77) وترميز البادئة وذاكرة التخزين المؤقت للألوان لضغط البيانات المجمّعة. تم فك ترميز السرعات الأسرع من تنسيق PNG إلى جانب ضغط أكثر كثافة بنسبة 25% مقارنةً باستخدامه بتنسيق PNG اليوم.
1 مقدمة
يصف هذا المستند تمثيل البيانات المضغوطة لصورة WebP بدون فقدان المعلومات. وهو مخصّص كمرجع مفصّل لبرنامج الترميز WebP بدون فقدان البيانات تنفيذ برنامج فك الترميز.
في هذا المستند، نستخدم على نطاق واسع بنية لغة البرمجة C لوصف
البثّ الثنائي ونفترض توفُّر دالة لقراءة الوحدات الثنائية،
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
- ذاكرة التخزين المؤقت للألوان
- صفيف صغير موجَّه إلى التجزئة لتخزين الألوان المستخدَمة مؤخرًا حتى تتمكّن من تذكُرها باستخدام رموز أقصر
- صورة فهرسة الألوان
- صورة أحادية الأبعاد للألوان التي يمكن فهرستها باستخدام عدد صحيح صغير (يصل إلى 256 ضمن WebP بدون فقدان البيانات).
- صورة تحويل الألوان
- صورة ثنائية الأبعاد لدرجة الدقة الفرعية وتحتوي على بيانات حول ارتباطات مكونات الألوان
- ربط المسافات
- تغيير مسافات LZ77 للحصول على أصغر قيم للبكسل في القرب من المستوىَين
- صورة إنتروبيا
- صورة ثنائية الأبعاد بدرجة دقة منخفضة تشير إلى ترميز معلومات المحتوى الذي يجب استخدامه في المربّع المعنيّ في الصورة، أي أنّ كل بكسل هو رمز ملف شخصي بادئ.
- LZ77
- خوارزمية ضغط للنوافذ المتحركة المستندة إلى القاموس، والتي تُصدر الرموز أو تصفها على أنّها تسلسلات من الرموز السابقة
- رمز البادئة الوصفية
- عدد صحيح صغير (يصل إلى 16 بت) يفهرس عنصرًا في جدول البادئة التعريفية .
- صورة متنبئ
- صورة ذات درجة دقة منخفضة ثنائية الأبعاد تشير إلى المتنبّئ المكاني الذي يتم استخدامه لمربّع معيّن في الصورة
- رمز البادئة
- طريقة كلاسيكية لتشفير المعلومات العشوائية يتم فيها استخدام عدد أقل من البتات للرموز الأكثر تكرارًا.
- ترميز البادئة
- طريقة لقصور بالأعداد الصحيحة الأكبر، التي يتم فيها ترميز بضع وحدات بت من العدد الصحيح باستخدام رمز إنتروبيا وينظم وحدات البت المتبقية الأولية. هذا يسمح أن تظل أوصاف رموز القصور صغيرة نسبيًا حتى عندما يكون نطاق الرموز كبيرًا.
- طلب مسح ضوئي
- ترتيب معالجة وحدات البكسل (من اليسار إلى اليمين ومن أعلى إلى أسفل)، بدءًا من من وحدة البكسل العلوية اليسرى. بعد إكمال صف، تابِع من عمود الصف التالي الأيمن.
3 رؤوس RIFF
تحتوي بداية الرأس على حاوية RIFF. وهذا يتألف من الـ 21 بايت التالية:
- سلسلة "RIFF".
- قيمة 32 بت بترتيب الوحدات الأقل أهمية لطول الجزء، وهو الحجم الكامل للجزء الذي يتحكّم فيه رأس RIFF عادةً، يساوي هذا حجم حمولة البيانات (حجم الملف مطروحًا منه 8 بايت: 4 بايت لـ "RIFF" 4 بايت لتخزين القيمة نفسها).
- سلسلة "WEBP" (اسم حاوية RIFF).
- السلسلة "VP8L" (FourCC لبيانات الصور التي تم ترميزها بدون فقدان)
- قيمة 32 بت بترتيب الوحدات الأقل أهمية لعدد البايتات في البث بدون فقدان البيانات
- توقيع مكوّن من بايت واحد 0x2f
تحدِّد أوّل 28 بت من بث البيانات عرض الصورة وارتفاعها. ويتم فك ترميز العرض والارتفاع كأعداد صحيحة 14 بت على النحو التالي:
int image_width = ReadBits(14) + 1;
int image_height = ReadBits(14) + 1;
تؤدي دقة 14 بت لعرض الصورة وارتفاعها إلى الحد من الحد الأقصى لحجم صورة WebP بدون فقدان التفاصيل إلى 16384 × 16384 بكسل.
إنّ القيمة البتية alpha_is_used هي مجرد تلميح، ومن المفترض ألا تؤثّر في عملية فك التشفير. يجب أن يتم تعيينها على 0 عندما تكون جميع قيم ألفا 255 في الصورة، و1 في الحالات الأخرى.
int alpha_is_used = ReadBits(1);
رقم_الإصدار هو رمز مكون من 3 بت يجب ضبطه على القيمة 0. ويجب التعامل مع أي قيمة أخرى كخطأ.
int version_number = ReadBits(3);
4 تحويلات
عمليات التحويل هي عمليات قابلة للعكس لتعديل بيانات الصورة التي يمكن أن تقلِّل من التشويش الرمزي المتبقّي عن طريق وضع نماذج للارتباطات المكانية واللونية. هم يمكن أن يجعل الضغط النهائي أكثر كثافة.
يمكن أن تخضع الصورة لأربعة أنواع من عمليات التحويل. يشير الرمز 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 تحويل المتنبئ
يمكن استخدام تحويل التوقّعات لتقليل التشويش من خلال الاستفادة من حقيقة أنّه غالبًا ما تكون هناك علاقة بين وحدات البكسل المجاورة. في عملية التحويل باستخدام المتنبّئ، تتم توقّع قيمة بكسل الحالية من وحدات البكسل التي تم فك ترميزها (بترتيب خطوط المسح) ولا يتم ترميز سوى القيمة المتبقية (القيمة الفعلية - القيمة المتوقّعة). يحدِّد المكوّن الأخضر للبكسل المؤشرات الـ 14 التي يتم استخدامها ضمن كتلة معيّنة من صورة ARGB. يحدد وضع التنبؤ نوع التنبؤ باستخدامه. نقسم الصورة إلى مربعات، وتمثل جميع وحدات البكسل في مربع يستخدمون نفس وضع التنبؤ.
أول 3 بتات من بيانات التنبؤ تحدد عرض القالب وارتفاعه في العدد من البت.
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 وضعًا مختلفًا للتوقّع. في كل وضع من أوضاع التنبؤ، يتم التنبؤ بقيمة البكسل من وحدة بكسل متجاورة أو أكثر تكون قيمها معروفة بالفعل.
لقد اخترنا وحدات البكسل المجاورة (TL وT وTR وL) للبكسل الحالي (P) على أنه التالي:
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 | Average2(L, T) |
8 | متوسط2(TL, T) |
9 | Average2(T, TR) |
10 | Average2(average2(L, TL), Average2(T, TR)) |
11 | Select(L, T, TL) |
12 | ClampAddSubtractFull(L, T, TL) |
13 | ClampAddSubtractHalf(Average2(L, T), TL) |
يتم تعريف Average2
على النحو التالي لكل مكوّن من مكوّنات ARGB:
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
لكل مكوّن ARGB على النحو التالي:
// 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، وتكون جميع وحدات البكسل في العمود الموجود في أقصى اليسار T-pixel.
تكون معالجة بكسل TR للبكسل في العمود الموجود في أقصى اليمين استثنائية. يتم التنبؤ بوحدات البكسل في العمود الموجود في أقصى اليسار باستخدام الأوضاع [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 لكل بكسل. يحافظ تحويل اللون على القيمة الخضراء (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 بت (int8) قبل استدعاء ColorTransformDelta()
. يجب تفسير القيمة التي تحمل علامة
كعدد تكميلي ثنائي بسعة 8 بت (أي أنّ نطاق uint8
[128..255] يتم ربطه بنطاق [-128..-1] لقيمة int8 المحوَّلة).
يجب إجراء عملية الضرب باستخدام دقة أكبر (بدقة 16 بت على الأقل). لا يهم خاصية إضافة العلامة الخاصة بعملية shift هنا؛ يتم استخدام أقل 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 طرح تأثير Green Transform
تطرح عملية التحويل "طرح الأخضر" قيم اللون الأخضر من قيم اللون الأحمر والأزرق لكل بكسل. وعند توفّر هذا التحويل، يجب أن تضيف أداة فك الترميز ترميز لكل من القيمتين الأحمر والأزرق. لا تتوفّر أي بيانات مرتبطة بهذه السلسلة من عمليات التحويل. يطبّق أداة فك التشفير التحويل العكسي على النحو التالي:
void AddGreenToBlueAndRed(uint8 green, uint8 *red, uint8 *blue) {
*red = (*red + green) & 0xff;
*blue = (*blue + green) & 0xff;
}
هذا التحويل متكرر، حيث يمكن نمذته باستخدام تحويل الألوان، ولكن نظرًا لعدم وجود بيانات إضافية هنا، يمكن إجراء تحويل الطرح الأخضر ترميزها باستخدام وحدات بت أقل من تحويل اللون كامل المنفوخ.
4.4 تحويل فهرسة الألوان
إذا لم يكن هناك العديد من قيم البكسل الفريدة، فقد يكون من الأفضل إنشاء مصفوفة فهرس الألوان واستبدال قيم البكسل بفهارس الصفيفة. اللون الذي يؤدي تحويل الفهرسة إلى تحقيق ذلك (في سياق WebP بدون فقدان المعلومات، لا نسميه تحديدًا تحويل لوحة الألوان لأنّ هناك مفهومًا مشابهًا ولكنه أكثر ديناميكية في ترميز WebP بدون فقدان المعلومات: ذاكرة التخزين المؤقت للألوان).
يتحقّق تحويل "فهرسة الألوان" من عدد قيم ARGB الفريدة في الصورة. إذا كان هذا العدد أقل من الحدّ الأدنى (256)، يتم إنشاء صفيف من قيم ARGB هذه، والتي يتم استخدامها بعد ذلك لاستبدال قيم البكسل بالفهرس المطابق: يتم استبدال القناة الخضراء للبكسل بالفهرس، ويتم ضبط جميع قيم ألفا على 255، وجميع قيم الأحمر والأزرق على 0.
تحتوي بيانات التحويل على حجم جدول الألوان والإدخالات في دالة اللون المؤقت. تقرأ أداة فك الترميز بيانات تحويل فهرسة الألوان على النحو التالي:
// 8-bit value for the color table size
int color_table_size = ReadBits(8) + 1;
يتم تخزين جدول الألوان باستخدام تنسيق تخزين الصور نفسه. يمكن الحصول على جدول الألوان
من خلال قراءة صورة بدون عنوان RIFF وحجم الصورة وعمليات
التحويل، بافتراض أنّ ارتفاع الصورة هو بكسل واحد وعرضها هو color_table_size
.
يتم ترميز جدول الألوان دائمًا بترميز الطرح لتقليل قصور الصورة. دلتا
من ألوان لوحة الألوان تحتوي عادةً على قصور أقل بكثير من الألوان
نفسها، ما يؤدي إلى توفير كبير في الصور الأصغر حجمًا. في فك الترميز،
كل لون نهائي في جدول الألوان عن طريق إضافة
قيم مكون اللون حسب كل مكون ARGB على حدة وتخزين أقل
8 بتات كبيرة من النتيجة.
إنّ عملية التحويل العكسي للصورة هي ببساطة استبدال قيم البكسل (التي هي مؤشرات إلى جدول الألوان) بقيم جدول الألوان الفعلية. تتم الفهرسة استنادًا إلى المكوّن الأخضر للون ARGB.
// Inverse transform
argb = color_table[GREEN(argb)];
إذا كان الفهرس يساوي color_table_size
أو يزيد عنه، يتم استخدام قيمة اللون argb
على 0x00000000 (أسود شفاف).
عندما يكون جدول الألوان صغيرًا (يساوي أو أقل من 16 لونًا)، فإن العديد من وحدات البكسل مجمعة في بكسل واحد. تعمل ميزة تجميع وحدات البكسل على تجميع عدة بكسل (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]. تشير القيمة 3
إلى دمج ثمانية بكسل وأنّ كل بكسل له نطاق من [0..1]،
أي قيمة ثنائية.
يتم تجميع القيم في المكوّن الأخضر على النحو التالي:
width_bits
= 1: لكل قيمة x، حيث تستخدم x ":" 0 (التعديل 2) رمز أخضر يتم وضع القيمة عند س في وحدات البت الأربعة الأقل أهمية القيمة الخضراء عند x / 2، والقيمة الخضراء عند x + 1 في 4 أهم وحدات بت للقيمة الخضراء بـ x / 2.width_bits
= 2: لكل قيمة x، حيث x ":" 0 (التعديل 4) يظهر رمز أخضر عند القيمة x في اثنين البت الأقل أهمية في القيمة الخضراء عند x / 4، والقيم الخضراء عند x + 1 إلى x + 3 في بالترتيب إلى وحدات البت الأكثر أهمية للقيمة الخضراء في س / 4.width_bits
= 3: لكل قيمة x، حيث x ":" 0 (التعديل 8) يظهر رمز أخضر يتم وضع القيمة عند س في أقل وحدة بت من اللون الأخضر القيمة على 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 ترميز بيانات الصور
لا يرتبط ترميز بيانات الصورة بدورها.
يتم تقسيم الصورة أولاً إلى مجموعة من الكتل ذات الحجم الثابت (عادةً ما تكون 16×16 كتلة). يتم وضع نماذج لكلّ من هذه الكتل باستخدام رموز المعلومات العشوائية الخاصة بها. كذلك، قد تشترك عدة كتل في نفس رموز الإنتروبيا.
الأسباب: ينطوي تخزين رمز قصور على تكلفة. يمكن تقليل هذه التكلفة إذا كانت الكتل المتشابهة إحصائيًا تتشارك رمزًا للقصور، ما يؤدي إلى تخزين هذا الرمز مرة واحدة فقط. على سبيل المثال، يمكن لبرنامج الترميز العثور على وحدات مشابهة من خلال تجميعها باستخدام خصائصها الإحصائية أو من خلال ربط زوج من المجموعات التي تم اختيارها بشكل عشوائي بشكل متكرر عندما يؤدي ذلك إلى تقليل إجمالي عدد الوحدات اللازمة لترميز الصورة.
يتم ترميز كل بكسل باستخدام إحدى الطرق الثلاث المحتملة:
- القيم الثابتة المُشفَّرة بالبادئة: يتم استخدام ترميز معلومات المحتوى (التشفير العشوائي) بشكل مستقل لكل قناة (الأخضر والأحمر والأزرق والألفا).
- LZ77 إشارة إلى المحتوى السابق: يتم نسخ تسلسل من البكسل من مكان آخر في الصورة.
- رمز ذاكرة التخزين المؤقت للألوان: استخدام رمز تجزئة مضاعف قصير (ذاكرة التخزين المؤقت للألوان) فهرس فقط للون الذي تمت رؤيته مؤخرًا.
تصف الأقسام الفرعية التالية كلًّا من هذه العناصر بالتفصيل.
5.2.1 رموز حرفية مشفّرة ببادئة
يتم تخزين وحدة البكسل كقيم مرمزة كبادئة، وهي الأخضر والأحمر والأزرق وألفا (في هذا الطلب). راجع القسم 6.2.3 للحصول على التفاصيل.
5.2.2 LZ77 Backward Reference
المراجع إلى الخلف هي مجموعات من الطول ورمز المسافة:
- يشير "الطول" إلى عدد وحدات البكسل التي يجب نسخها بترتيب خطوط المسح.
- رمز المسافة هو رقم يشير إلى موضع جهاز معروض من قبل الذي سيتم نسخ وحدات البكسل منه. يمكنك الاطّلاع على عملية الربط الدقيقة أدناه.
يتم تخزين قيم الطول والمسافة باستخدام ترميز البادئة LZ77.
يقسم ترميز بادئة LZ77 القيم الصحيحة الكبيرة إلى جزأين: رمز البادئة والبتات الإضافية. يتم تخزين رمز البادئة باستخدام رمز القصور، بينما يتم تخزين وحدات البت الإضافية كما هي (بدون رمز قصور).
الأسباب: يؤدي هذا النهج إلى تقليل متطلبات مساحة التخزين للإنتروبيا. الرمز. بالإضافة إلى ذلك، تكون القيم الكبيرة نادرة في العادة، لذا سيتم استخدام بتات إضافية لعدة قيم في الصورة. وبالتالي، ينتج عن هذه الطريقة ضغط أفضل بوجه عام.
يشير الجدول التالي إلى رموز البادئة والبتات الإضافية المستخدَمة لتخزين نطاقات مختلفة من القيم.
نطاق القيمة | رمز البادئة | معلومات إضافية |
---|---|---|
1 | 0 | 0 |
2 | 1 | 0 |
3 | 2 | 0 |
4 | 3 | 0 |
6.5 | 4 | 1 |
8.7 | 5 | 1 |
12.9. | 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] هي رموز خاصة ويتم حجزها للإغلاق. بجوار البكسل الحالي. يتكون هذا الحي من 120 بكسل:
- وحدات البكسل التي تقع بين صف واحد و7 صفوف فوق وحدات البكسل الحالية وتصل إلى 8 أعمدة
على يمين وحدات البكسل الحالية أو تصل إلى 7 أعمدة على يسار وحدات البكسل الحالية [إجمالي
وحدات البكسل هذه =
7 * (8 + 1 + 7) = 112
]. - وحدات البكسل التي تكون في الصف نفسه الذي يتضمّن وحدات البكسل الحالية وتكون ضمن 8
أعمدة على يمين وحدات البكسل الحالية [
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 بكسل)
الفرق في الاتجاه س وفرق 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).
يتم تخزين رموز ذاكرة التخزين المؤقت للألوان على النحو التالي. أولاً، هناك قيمة وحدة بت واحدة إلى ما إذا كان سيتم استخدام ذاكرة التخزين المؤقت للألوان. إذا كان هذا العنصر الثنائي هو 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)
. يتم إجراء عملية بحث واحدة فقط في ذاكرة التخزين المؤقت للألوان، ولا يتم حلّ أي
تعارض.
في بداية فك ترميز الصورة أو ترميزها، تكون جميع الإدخالات بجميع الألوان يتم تعيين قيم ذاكرة التخزين المؤقت على صفر. يتم تحويل رمز ذاكرة التخزين المؤقت للون إلى هذا اللون عند وقت فك الترميز. يتم الاحتفاظ بحالة ذاكرة التخزين المؤقت للألوان عن طريق إدخال كل pixel، سواء تم إنتاجه بالإشارة إلى الخلف أو كقيم حرفية، في ذاكرة التخزين المؤقت في بالترتيب الذي تظهر به في ساحة المشاركات.
رمز الإنتروبيا 6
6.1 نظرة عامة
ويتم ترميز معظم البيانات باستخدام رمز بادئة أساسي. وبالتالي، يتم إرسال الرموز من خلال إرسال أطوال رموز البادئة، على النحو التالي: بدلاً من رموز البادئات الفعلية.
وعلى وجه الخصوص، يستخدم التنسيق ترميز بادئة الصيغة المكانية. بعبارة أخرى، بكلمات، يمكن أن تستخدم كتل مختلفة من الصورة قصورًا مختلفًا الرموز.
الأسباب: قد تكون للمناطق المختلفة من الصورة خصائص مختلفة. لذا فإن السماح لهم باستخدام رموز إنتروبيا مختلفة يوفر مزيدًا من المرونة من المحتمل أن يكون ضغطها أفضل.
6.2 التفاصيل
تتكوّن بيانات الصورة المرمّزة من عدة أجزاء:
- فك ترميز رموز البادئة وإنشاؤها.
- رموز البادئة الوصفية
- بيانات الصور المشفرة بالإنتروبيا.
بالنسبة لأي وحدة بكسل محددة (x، y)، تكون هناك مجموعة من خمسة رموز بادئة مرتبطة بها. في ما يلي هذه الرموز (بترتيب بث الوحدات)
- رمز البادئة رقم 1: يتم استخدامه للقناة الخضراء وطول المرجع السابق و ذاكرة التخزين المؤقت للألوان.
- رمز البادئة 2 و3 و4: تُستخدَم لقنوات الأحمر والأزرق والشفافية، على التوالي.
- رمز البادئة رقم 5: يتم استخدامه لمسافة المرجع القديم.
من الآن فصاعدًا، سنشير إلى هذه المجموعة باسم مجموعة رموز البادئة.
6.2.1 فك ترميز رموز البادئة وإنشاؤها
يصف هذا القسم كيفية قراءة أطوال رمز البادئة من البث المباشر للبيانات.
يمكن ترميز أطوال رموز البادئة بطريقتين. يتم تحديد الطريقة المستخدَمة بقيمة 1 بت.
- إذا كان هذا الرمز الثنائي هو 1، يعني ذلك أنّه رمز طول رمز بسيط.
- إذا كانت قيمة هذا العنصر هي 0، يعني ذلك أنّه رمز طول رمز عادي.
وفي كلتا الحالتين، يمكن أن تكون هناك أطوال رموز غير مستخدمة لا تزال جزءًا من دفق. قد لا يكون هذا الإجراء فعّالاً، ولكنّه مسموح به بموجب التنسيق. يجب أن تكون الشجرة الموصوفة شجرة ثنائية كاملة. تُعدّ العقدة الورقية الفردية شجرة ثنائية كاملة ويمكن ترميزها باستخدام رمز طول الرمز البسيط أو رمز طول الرمز العادي. عند ترميز ملف واحد للعقدة باستخدام رمز طول الرمز العادي، تكون جميع أطوال الرموز صفرًا باستثناء طول رمز واحد، ويتم وضع علامة على قيمة الملف الواحد للعقدة بطول 1، حتى في حال عدم استخدام أي بتات عند استخدام شجرة الملف الواحد للعقدة.
رمز طول الرمز البسيط
يتم استخدام هذه الصيغة في الحالة الخاصة عندما يكون هناك رمز واحد أو رمزين من البادئة فقط.
النطاق [0..255] مع طول الرمز 1
. جميع أطوال رموز البادئة الأخرى
تكون صفرًا ضمنيًا.
يشير الرمز الأول إلى عدد الرموز:
int num_symbols = ReadBits(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
.
رمز طول الرمز العادي
ويتناسب أطوال رمز البادئة مع 8 بتات وتتم قراءتها على النحو التالي.
أولاً، تحدّد السمة 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
، يتم ضبط الحد الأقصى لعدد الرموز المختلفة التي يتم قراءتها
(max_symbol
) لكل نوع رمز (A وR وG وB والمسافة) على
حجم الأبجدية:
- قناة 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.
صورة إنتروبيا
تحدد صورة القصور أي رموز بادئة يتم استخدامها في أجزاء مختلفة من .
تحتوي الأوصياء الثلاثة الأولى على قيمة 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;
بناءً على وحدة البكسل (x، y) في صورة ARGB، يمكننا الحصول على البادئة المقابلة الرموز التي سيتم استخدامها على النحو التالي:
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
التي represent مجموعة من خمسة رموز بادئة. أيضًا، prefix_code_groups
عبارة عن صفيف من
PrefixCodeGroup
(بالحجم num_prefix_groups
).
بعد ذلك، يستخدم وحدة الترميز مجموعة رموز البادئة prefix_group
لفك ترميز بكسل (x, y)، كما هو موضّح في "فك ترميز بيانات
الصورة المُشفَّرة بالترميز العشوائي".
6.2.3 فك ترميز بيانات الصور المشفَّرة على الإنترنت
بالنسبة إلى الموضع الحالي (x, y) في الصورة، يحدِّد أداة فك التشفير أولاً مجموعة رموز البادئة المقابلة (كما هو موضّح في القسم الأخير). استنادًا إلى مجموعة رمز البادئة، تتم قراءة وحدة البكسل وفك ترميزها على النحو التالي.
بعد ذلك، اقرأ الرمز S من بث البتات باستخدام رمز البادئة رقم 1. لاحظ أن S هي
أي عدد صحيح في النطاق من 0
إلى
(256 + 24 +
color_cache_size
- 1)
يعتمد تفسير S على قيمته:
- إذا كان S < 256
- استخدم S كمكون أخضر.
- اقرأ اللون الأحمر من بث البتات باستخدام رمز البادئة رقم 2.
- اقرأ اللون الأزرق من مصدر البيانات البت باستخدام رمز البادئة رقم 3.
- اقرأ المحتوى النصي من بث البتات باستخدام رمز البادئة رقم 4.
- إذا كان S >= 256 وS < 256 + 24
- استخدِم S - 256 كرمز لبادئة الطول.
- يمكنك قراءة وحدات بت إضافية للطول من البث المباشر للبيانات.
- حدد طول المرجع السابق L من رمز بادئة الطول قراءة وحدات البت الإضافية.
- اقرأ رمز بادئة المسافة من مصدر البيانات البتّي باستخدام رمز البادئة رقم 5.
- قراءة وحدات بت إضافية للمسافة من بث البتات
- حدِّد المسافة D للإشارة إلى المحتوى السابق من رمز بادئة المسافة والبتات الإضافية التي تم قراءتها.
- نسخ L بكسل (بترتيب خطوط المسح) من تسلسل البكسل بدءًا من الموضع الحالي مطروحًا منه D بكسل
- إذا كان S >= 256 + 24
- استخدِم S - (256 + 24) كمؤشر في ذاكرة التخزين المؤقت للألوان.
- الحصول على لون ARGB من ذاكرة التخزين المؤقت للألوان في هذا الفهرس
7 البنية العامة للتنسيق
فيما يلي عرض بالتنسيق في "صيغة باكوس ناور المعززة" (ABNF) RFC 5234 RFC 7405 ولا يشمل كل التفاصيل. لا يتم ترميز نهاية الصورة (EOI) إلا بشكل ضمني في عدد البكسل (image_width * image_height).
يُرجى العِلم أنّ السمة *element
تعني أنّه يمكن تكرار الحقل element
0 مرة أو أكثر. 5element
تعني أنّ السمة element
تتكرّر 5 مرات بالضبط. يمثّل الرمز %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