ما هي الصورة أصلاً؟
قبل أن نتكلّم عن "ضغط الصور"، يجب أن نتّفق على ما هي الصورة كبيانات. كل صيغة في المنهج — من GIF إلى JPEG XL — ليست إلا طريقة أذكى لكتابة المصفوفة نفسها التي سنبنيها هنا بأيدينا.
- اللغز: كم يكلّف تخزين صورة واحدة خام؟
- الصورة كشبكة أرقام — sampling و quantization
- القنوات، عمق البِت، والتخطيط في الذاكرة
- تمرين: ابنِ صورة من العدم واحسب ثمنها
شاشة هاتف حديثة: 2532 × 1170 بِكسل. تريد تخزين صورة فوتوغرافية
واحدة تملأها، بجودة لا تفرّق العين بينها وبين المشهد.
كم بايتاً تحتاج دون أي ضغط؟ احسبها الآن — قرّر كم لوناً يجب أن يميّزه كل بِكسل حتى لا ترى العين "أحزمة" في تدرّج السماء.
ثم: لو أرسل مليون مستخدم صورة كهذه يومياً، كم يكلّفك ذلك من نقل بيانات شهرياً؟ ولماذا — رغم رخص التخزين — يظلّ الرقم كارثياً؟ اكتب تقديرك على ورقة قبل أن تكمل. الرقم الذي ستصل إليه هو كل الدافع وراء المنهج.
الصورة كشبكة من الأرقام
الضوء الواصل لعينك حقلٌ متّصل: توزيع مستمرّ للطاقة عبر المكان والطول الموجي. لكن الحاسوب لا يعرف إلا الأعداد المنفصلة. فأول قرار في تاريخ الصور الرقمية: كيف نحوّل المتّصل إلى منفصل؟ عمليتان ستطاردانك حتى آخر المنهج:
تقطيع المكان وتقطيع القيمة سيعودان بالضبط في قلب الضغط الخَسور (العقدة ٠٥). الضغط الخَسور ليس إلا "أخذ عيّنات وتكميم أذكى". احفظ هذه الجملة؛ ستفهمها بعمق لاحقاً.
القنوات وعمق البِت
كل بِكسل لون = عادةً ثلاثة أعداد RGB. لماذا ثلاثة بالذات؟
سؤال عميق عن فسيولوجيا العين، نؤجّله بالكامل للعقدة ٠٤. كل قناة تُخزَّن بعدد
ثابت من البِتّات = عمق البِت. الشائع ٨ بِت → ٢٥٦ مستوى →
١٦.٧ مليون لون.
تخيّل تدرّجاً ناعماً للسماء بـ١٦ مستوى فقط على عرض ٢٠٠٠ بِكسل. كم بِكسلاً
يحصل على نفس القيمة قبل القفزة التالية؟ ستراها العين كأحزمة
(banding). هذه أول مقايضة في حياتك بين الحجم والجودة المُدرَكة.
التخطيط في الذاكرة و stride
الذاكرة أحادية البُعد، والصورة ثنائية. نُسطّح صفّاً صفّاً (row-major):
offsetoffset = (y * width + x) * bytes_per_pixel
ويظهر stride = عدد البايتات من بداية صفّ لبداية الصفّ
التالي. كثيراً ما يكون أكبر من width * bpp لمحاذاة الأداء.
stride ليس بالضرورة عرض الصورة. الخلط بينهما يُنتج صوراً "منحرفة قطرياً" — لأن كل صفّ يُقرأ بإزاحة خاطئة فينزلق تدريجياً.
اكتب — بلا أي مكتبة صور — برنامجاً:
- يُنشئ مصفوفة بايتات RGB عرضها W وارتفاعها H، مُسطّحة row-major.
- يرسم تدرّجاً: الأحمر
= x*255/(W-1)، الأخضر= y*255/(H-1)، الأزرق= 128. احسب كل إزاحة بيدك. - يكتب الناتج بصيغة PPM (P6) — أبسط صيغة على الإطلاق: ترويسة نصّية ثم بايتات خام:
PPM P6
P6\n <width> <height>\n 255\n <البايتات الخام: W*H*3> - اطبع الحجم الفعلي بالبايت. قارنه بحسابك في اللغز.
القيود: ممنوع أي مكتبة ترميز صور. احسب كل إزاحة بيدك، اشعر بالتسطيح. لا تنتقل حتى ترى صورتك تُفتح في عارض — رؤية بايتاتك تتحوّل تدرّجاً هي أول لحظة "آها".
الصورة = sampling (تقطيع المكان) + quantization
(تقطيع القيمة). حجمها الخام = W×H×channels×(depth/8) = ضخم بلا
احتمال (≈٩MB للصورة الواحدة) — هذا هو العدوّ. ولاحظنا دون أن
نستغلّ بعد: البِكسلات المتجاورة متشابهة جداً. فيها "هواء". هذا التشابه
هو ثغرة العدوّ، وكل المنهج حملةٌ ضدّه.