> ## Content Index
> Fetch the complete content index at: https://arabroot.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# صيغ الصور: كيف تختار الصيغة المناسبة لموقعك
- URL: https://arabroot.io/articles/صيغ-الصور-وكيف-تختار-بينها/
- Published: 2026-10-10T06:00:00.000Z
- Updated: 2026-10-09T14:42:29.000Z
- Description: كيف تحفظ كل صيغة صور البكسلات والألوان، ولماذا يصغر الملف نفسه إلى الثلث أو أقل عندما تختار الصيغة والمقاس المناسبين.
- Author: فريق عرب رووت
- Tags: الأدلة التقنية, أساسيات الحاسب والبرمجة, DevOps وCI/CD, الاستضافة الذاتية

التقط مصور صورة الغروب التي في هذا المقال بكاميرا احترافية، ووصل ملفها الأصلي إلى 17.8 MB، فإذا وضعتها كما هي في صفحة موقعك فسوف ينتظر الزائر على هاتفه حتى تنزل كاملة، بينما يكفيه منها ملف حجمه 68 KB تقريباً لا يكاد يميزه عن الأصل. والفرق بين الرقمين ليس سحراً، وإنما هو اختيار الصيغة Format المناسبة لنوع الصورة، والمقاس المناسب للشاشة، وإعدادات الضغط الصحيحة. وفي المقابل فإن الصيغة الخطأ تفسد الصورة: نص يصبح مشوشاً في JPEG، وغروب يمتلئ بالنقاط في GIF، وشعار يصبح ضبابياً عند التكبير لأنه حفظ كصورة نقطية.

وهذا المقال من مرحلة [أساسيات علوم الحاسب Computer Science Fundamentals](https://arabroot.io/start/#stage-foundations)، ويفترض أنك تعرف البت والبايت والـ Hex من مقال [الأنظمة العددية للمبرمجين](https://arabroot.io/articles/%D8%A7%D9%84%D8%A7%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%B9%D8%AF%D8%AF%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%AB%D9%86%D8%A7%D8%A6%D9%8A-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/). وسوف نناقش في هذا المقال ما يلي:

- الفرق بين الصورة النقطية Raster والصورة المتجهة Vector، وما الذي يحفظه الملف فعلاً لكل بكسل: عمق الألوان وفضاء الألوان والشفافية.
- الضغط مع الفقد Lossy ودونه Lossless، ثم كل صيغة مشهورة من الداخل: JPEG وPNG وGIF وWebP وAVIF وJPEG XL وHEIC وSVG وICO، ودعم المتصفحات لكل منها في أكتوبر 2026.
- البيانات الوصفية Metadata داخل الصورة، وما الذي تكشفه عنك.
- تجربة عملية: نفس الصورة ونفس الرسم بكل الصيغ بجودة متقاربة، مع الأحجام الحقيقية ومقياس التشابه SSIM، ثم SVG مقابل PNG لشعار.
- كيف تختار الصيغة، وأفضل الممارسات على الويب: الصور المتجاوبة Responsive Images والتحميل المؤجل Lazy Loading وخدمات تصغير الصور عند الطلب.

## الصورة النقطية Raster والصورة المتجهة Vector

هناك طريقتان مختلفتان تماماً لحفظ أي صورة، فالصورة النقطية Raster تقسم الصورة إلى شبكة من المربعات الصغيرة اسمها البكسلات Pixels، وتحفظ لون كل بكسل منها، وهذا ما تفعله الكاميرا ولقطة الشاشة وصيغ JPEG وPNG وWebP وAVIF. أما الصورة المتجهة Vector فلا تحفظ أي بكسل، وإنما تحفظ وصف الأشكال: دائرة مركزها هنا ونصف قطرها كذا ولونها برتقالي، ثم يرسمها المتصفح أو البرنامج عند العرض بالحجم المطلوب، وأشهر صيغها على الويب SVG. والمثال الأقرب من الحياة هو الفرق بين صورة لخريطة مطبوعة، تكبرها بالعدسة فترى نقاط الحبر، وبين وصف مكتوب للطريق تستطيع أن ترسمه على ورقة بأي حجم.

الصورة التالية تبين نفس الشعار بالطريقتين، ثم بعد تكبيره ثماني مرات:

![لوحتان: على اليمين شعار دائري برتقالي محفوظ كشبكة 24 في 24 بكسل، وعند تكبيره تظهر حافته كدرج من المربعات، وعلى اليسار نفس الشعار محفوظ كدائرة في SVG، وعند تكبيره يبقى ناعماً، وتحته سطر الكود الذي يصف الدائرة](https://arabroot.io/content/images/2026/10/image-formats-01-raster-vector.webp)

النقطية تحفظ البكسلات فتتشوه عند التكبير، والمتجهة تحفظ الشكل فترسم بأي حجم

ولذلك فالقاعدة الأولى بسيطة: ما رسم بالأشكال، مثل الشعارات والأيقونات والرسوم البيانية والمخططات، يحفظ متجهاً إذا أمكن، وما التقط من الواقع، مثل الصور الفوتوغرافية، لا يمكن أن يكون إلا نقطياً، والسبب أنه لا يوجد وصف هندسي لوجه إنسان أو لغيمة. وقد يتساءل البعض: لماذا لا نحفظ كل شيء متجهاً ما دام لا يتشوه؟ والإجابة أن ملف SVG يكبر مع عدد الأشكال وتعقيدها، ويحتاج المتصفح أن يرسمه في كل مرة، فصورة فوتوغرافية محولة إلى ملايين المضلعات ستكون أكبر وأبطأ من JPEG بكثير.

## ماذا يحفظ الملف لكل بكسل؟ العمق والألوان والشفافية

كل بكسل في الصورة الملونة العادية مكون من ثلاث قنوات Channels: أحمر R وأخضر G وأزرق B، وكل قناة رقم بين 0 و255 أي بايت واحد، فالبكسل البرتقالي في شعار عرب رووت هو 233 و84 و32، أو بالـ Hex `E9 54 20`. وعدد البتات لكل قناة اسمه عمق الألوان Colour Depth، وثماني بتات تعني 256 مستوى لكل قناة، أي 16,777,216 لوناً ممكناً، وهذا ما تستخدمه أغلب صور الويب، بينما يحتاج HDR إلى 10 بتات أو أكثر، وقد شرحنا سبب ذلك والتدرج المتقطع Banding في [مقال الشاشة من الداخل](https://arabroot.io/articles/%D9%83%D9%8A%D9%81-%D8%AA%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D8%B4%D8%A7%D8%B4%D8%A9-%D9%85%D9%86-%D8%A7%D9%84%D8%AF%D8%A7%D8%AE%D9%84/#colour-depth).

وقد تضيف الصورة قناة رابعة اسمها ألفا Alpha تحدد شفافية كل بكسل، من 0 أي شفاف تماماً إلى 255 أي معتم تماماً، وهي التي تسمح لشعار أن يظهر فوق أي خلفية دون مربع أبيض حوله. ولاحظ أن JPEG لا يدعم الشفافية أصلاً، وهذا أحد أسباب بقاء PNG حتى اليوم.

أما فضاء الألوان Colour Space فهو الذي يحدد معنى هذه الأرقام: أي أحمر بالضبط هو الرقم 255؟ والفضاء الافتراضي على الويب هو [sRGB](https://www.w3.org/Graphics/Color/sRGB?ref=arabroot.io)، فإذا لم تحمل الصورة أي معلومات عن فضائها افترض المتصفح أنها sRGB. وهناك فضاءات أوسع مثل Display P3 الموجود في شاشات الهواتف والحواسيب الحديثة، وتصفه مواصفة [CSS Color 4](https://www.w3.org/TR/css-color-4/?ref=arabroot.io)، وAdobe RGB الذي تستخدمه الكاميرات الاحترافية. وتحمل الصورة فضاءها في ملف تعريف ألوان ICC Profile مدمج داخلها، فإذا حذفته دون أن تحول الألوان إلى sRGB أولاً ظهرت الألوان باهتة أو مختلفة، وصورة الاختبار في هذا المقال مثال حقيقي على ذلك كما سوف نرى في التجربة، فملفها الأصلي محفوظ بفضاء Adobe RGB.

والآن لنحسب حجم الصورة دون أي ضغط، والصورة التالية تبين ذلك على صورة الاختبار نفسها:

![ثلاث لوحات: بكسل واحد مكبر من صورة الغروب، ثم قنواته الأربع R وG وB وA بقيمها 233 و84 و32 و255، وأن 8 بتات تعطي 256 مستوى و16.7 مليون لون، ومثلثا sRGB وDisplay P3، ثم ثلاثة أشرطة: الحجم الخام 6,480,000 بايت وPNG بحجم 2,748,863 بايت وJPEG بحجم 119,715 بايت](https://arabroot.io/content/images/2026/10/image-formats-02-pixel-bytes.webp)

صورة 1200 في 1800 بكسل تحتاج 6.48 MB خاماً، وJPEG يصل بها إلى 120 KB تقريباً

لاحظ أن الحساب بسيط: 1200 × 1800 بكسل × 3 بايتات = 6,480,000 بايت، وهذا ما تحتاجه الصورة في الذاكرة عندما يعرضها المتصفح مهما كانت صيغتها، أما الملف على القرص وفي الشبكة فهو الذي تختلف فيه الصيغ، ومن هنا جاء كل ما في بقية المقال.

## الضغط دون فقد Lossless والضغط مع الفقد Lossy

الضغط دون فقد Lossless يعني أنك عندما تفك الملف تحصل على نفس البكسلات بالضبط، وهو ما تفعله PNG، وهذا ممكن لأن الصورة فيها تكرار: مساحة بيضاء كبيرة، أو صف يشبه الصف الذي فوقه. وأما الضغط مع الفقد Lossy فيحذف عن قصد تفاصيل لا تلاحظها العين، مثل الفروق الدقيقة في اللون بين بكسلين متجاورين، فلا يعود الملف مطابقاً للأصل أبداً، ولكنه يصغر عشرات المرات. وقد شرحنا كيف يعمل الضغط نفسه، من الإنتروبيا Entropy إلى Huffman وDEFLATE، في مقال [كيف يعمل ضغط البيانات](https://arabroot.io/articles/%D9%83%D9%8A%D9%81-%D9%8A%D8%B9%D9%85%D9%84-%D8%B6%D8%BA%D8%B7-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-compression/)، وهنا نركز على ما يخص الصور.

ولقياس «كم فقدنا» لا يكفي أن تنظر بعينك، ولذلك نستخدم في التجربة مقياس التشابه البنيوي SSIM، الذي نشره [Wang وزملاؤه في 2004](https://ieeexplore.ieee.org/document/1284395?ref=arabroot.io)، وهو يقارن الإضاءة والتباين والبنية بين الصورتين ويعطي رقماً، حيث 1 تعني تطابقاً تاماً، وكلما اقترب من 1 قل الفرق الذي يلاحظه الإنسان. وهذا المقياس نفسه هو الذي استخدمناه للفيديو في [تجربة ضغط فيديو الكاميرات](https://arabroot.io/articles/%D8%A7%D9%86%D9%88%D8%A7%D8%B9-%D9%83%D8%A7%D9%85%D9%8A%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D8%A7%D9%82%D8%A8%D8%A9-%D9%88%D9%83%D9%8A%D9%81-%D8%AA%D8%AE%D8%AA%D8%A7%D8%B1-%D8%A8%D9%8A%D9%86%D9%87%D8%A7/#codec-lab).

## JPEG: صيغة الصور الفوتوغرافية منذ 1992

صدرت مواصفة JPEG من الاتحاد الدولي للاتصالات تحت اسم [ITU-T T.81](https://www.w3.org/Graphics/JPEG/itu-t81.pdf?ref=arabroot.io) في 1992، وما زالت حتى اليوم الصيغة التي تفتح في كل جهاز وكل برنامج. والفكرة التي جعلتها تنجح أنها تحذف أولاً ما تضعف العين في رؤيته، والصورة التالية تبين خطواتها الست:

![ست بطاقات من اليمين إلى اليسار: تحويل RGB إلى YCbCr، ثم تقليل دقة اللون 4:2:0، ثم تقسيم الصورة إلى كتل 8 في 8، ثم تحويل DCT إلى ترددات، ثم التكميم Quantisation حيث تصبح أغلب القيم صفراً وهو رقم الجودة، ثم ترميز Huffman إلى ملف jpg](https://arabroot.io/content/images/2026/10/image-formats-03-jpeg-steps.webp)

الخطوة الخامسة وحدها هي التي يحددها رقم الجودة، وهي مصدر أغلب الفقد

وبالتفصيل:

1. **تحويل الألوان إلى YCbCr:** تفصل الصورة إلى قناة إضاءة Y وقناتي لون Cb وCr، والسبب أن العين ترى تفاصيل الإضاءة أدق بكثير من تفاصيل اللون.
2. **تقليل دقة الألوان Chroma Subsampling:** تحفظ قيمة لون واحدة لكل أربعة بكسلات في الوضع 4:2:0، فيذهب نصف البيانات قبل أي حساب، وقد شرحنا هذه الفكرة بالتفصيل في [مقال مفاهيم الفيديو](https://arabroot.io/articles/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#chroma) لأن الفيديو يستخدمها بنفس الطريقة.
3. **الكتل 8 × 8:** تقسم كل قناة إلى كتل من 64 بكسل، وتعالج كل كتلة وحدها، ولهذا ترى في الصور شديدة الضغط مربعات واضحة.
4. **تحويل DCT:** اختصار Discrete Cosine Transform، ويحول الكتلة من 64 قيمة بكسل إلى 64 قيمة تردد: الزاوية العليا اليسرى هي اللون العام للكتلة، وكلما اتجهت إلى الأسفل واليمين كانت التفاصيل الأدق. ولم نحذف شيئاً حتى الآن، فالتحويل نفسه يمكن عكسه.
5. **التكميم Quantisation:** تقسم كل قيمة على رقم من جدول ثم تقرب إلى أقرب عدد صحيح، فتصبح أغلب قيم التفاصيل الدقيقة صفراً، وهنا يحدث الفقد. ورقم الجودة Quality الذي تختاره، من 1 إلى 100، هو الذي يحدد حجم هذه الأرقام، فالجودة الأقل تعني قسمة على أرقام أكبر وأصفاراً أكثر.
6. **الترميز دون فقد:** ترتب القيم بحيث تتجمع الأصفار في النهاية، ثم ترمز بـ Huffman، فسلسلة طويلة من الأصفار لا تكلف إلا بتات قليلة.

وهناك خياران آخران تراهما في كل أداة. الأول JPEG التدريجي Progressive، الذي يرسل الصورة على مراحل فيرى الزائر نسخة ضبابية كاملة ثم تتضح، بدل أن يرى الصورة تنزل من الأعلى سطراً سطراً، وغالباً يكون أصغر قليلاً كما سوف نرى في التجربة. والثاني هو وضع تقليل الألوان نفسه، فالصورة الفوتوغرافية لا تتأثر بـ 4:2:0، ولكن النص الملون الرفيع ولقطات الشاشة تظهر حوافها مشوشة، ولذلك فإن JPEG هو أسوأ خيار للقطات الشاشة والرسوم التي فيها نص، وسوف نرى ذلك بالأرقام والصور.

## PNG: الضغط دون فقد والشفافية

ظهرت PNG في منتصف التسعينات كبديل مفتوح لـ GIF، وأحدث مواصفاتها هي [الإصدار الثالث من W3C](https://www.w3.org/TR/png-3/?ref=arabroot.io) الذي أصبح توصية رسمية في 24 يونيو 2025، وأضاف رسمياً الصور المتحركة APNG ودعم HDR. وطريقتها في الضغط على مرحلتين: الأولى مرشح Filter لكل صف يحول قيم البكسلات إلى الفرق بينها وبين جيرانها، مثل الفرق عن البكسل الذي على اليسار أو الذي فوقه، فتتحول المساحة المتدرجة إلى أرقام صغيرة متكررة، والثانية ضغط هذه الأرقام بـ DEFLATE، وهي نفس خوارزمية gzip وZIP الموصوفة في [RFC 1951](https://datatracker.ietf.org/doc/html/rfc1951?ref=arabroot.io).

وتحفظ PNG البكسلات بطريقتين أساسيتين:

- **الألوان الكاملة Truecolour:** ثلاثة أو أربعة بايتات لكل بكسل، أي كل الألوان الممكنة، وهي الصيغة الافتراضية لأغلب البرامج.
- **لوحة الألوان Palette:** وتسمى أيضاً PNG-8، حيث يحفظ الملف قائمة من 256 لوناً على الأكثر، ويحفظ لكل بكسل رقم لونه في القائمة أي بايت واحد، فإذا كانت الصورة فيها ألوان قليلة، مثل رسم بياني أو أيقونة أو لقطة شاشة لواجهة، صغر الملف كثيراً دون فرق ملحوظ. أما الصورة الفوتوغرافية فتفقد ألوانها وتظهر فيها خطوط التدرج.

ولاحظ أن PNG مع صورة فوتوغرافية خيار سيئ، والسبب أن الصورة الحقيقية فيها ضوضاء Noise من الكاميرا، فلا يجد DEFLATE تكراراً كافياً، وسوف ترى في التجربة أن PNG لصورة الغروب أكبر من JPEG بـ 23 مرة.

## GIF: 256 لوناً وصورة متحركة

صيغة GIF من 1987، وآخر مواصفاتها [GIF89a](https://www.w3.org/Graphics/GIF/spec-gif89a.txt?ref=arabroot.io) من 1989، وهي تضغط دون فقد بخوارزمية LZW، ولكنها لا تحفظ أكثر من 256 لوناً في الإطار الواحد، وشفافيتها إما شفاف أو معتم بلا درجات بينهما. وما أبقاها حية هو الحركة، فالملف الواحد يحمل عدة إطارات. والمشكلة أن تحويل صورة فوتوغرافية إلى 256 لوناً يحتاج إلى خلط الألوان بالنقاط Dithering حتى يخفي التدرج المتقطع، فيصبح الملف كبيراً ومليئاً بالنقاط. وبالنسبة للحركة فالبديل الأنسب اليوم هو مقطع فيديو MP4 أو WebM قصير يعمل تلقائياً دون صوت، فهو أصغر بكثير لأن ترميز الفيديو يحفظ الفرق بين الإطارات كما شرحنا في [مقال مفاهيم الفيديو](https://arabroot.io/articles/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#codec)، بينما GIF يحفظ كل إطار كصورة.

## الصيغ الحديثة: WebP وAVIF وJPEG XL وHEIC

كل الصيغ في هذا القسم تدعم الضغط مع الفقد ودونه والشفافية في نفس الصيغة، وهذا وحده يغني عن الاختيار بين JPEG وPNG، والفرق بينها في الكفاءة ودعم المتصفحات والرخص.

### WebP

أعلنتها Google في 2010، والضغط مع الفقد فيها مبني على ترميز إطار واحد من فيديو VP8، ولها وضع آخر دون فقد مختلف تماماً، ونشرت مواصفتها في [RFC 9649](https://datatracker.ietf.org/doc/html/rfc9649?ref=arabroot.io) في نوفمبر 2024، والأداة الرسمية لها `cwebp` من [مكتبة libwebp](https://developers.google.com/speed/webp?ref=arabroot.io). وهي اليوم مدعومة في كل المتصفحات الحديثة، وفي التجربة أعطت ملفاً أصغر من JPEG بنحو 28% بنفس SSIM، وأصغر ملف دون فقد تقريباً للرسم.

### AVIF

AVIF هي إطار واحد مضغوط بترميز الفيديو AV1 داخل حاوية HEIF، ومواصفتها من تحالف [Alliance for Open Media](https://aomediacodec.github.io/av1-avif/?ref=arabroot.io) الذي يطور AV1 دون رسوم براءات اختراع، والأداة المرجعية لها [libavif](https://github.com/AOMediaCodec/libavif?ref=arabroot.io) ومنها `avifenc`. وهي في التجربة أصغر صيغة للصورة الفوتوغرافية بفارق واضح، فقد وصلت إلى نفس SSIM بملف أصغر من JPEG بنحو 44%. ولكن لاحظ أمرين: الترميز أبطأ من JPEG وWebP، ووضعها دون فقد ضعيف، فقد كان في التجربة أكبر من PNG العادي للرسم بأكثر من مرتين.

### JPEG XL

JPEG XL هي المعيار ISO/IEC 18181 من [لجنة JPEG](https://jpeg.org/jpegxl/?ref=arabroot.io)، والمكتبة المرجعية [libjxl](https://github.com/libjxl/libjxl?ref=arabroot.io)، ومن مزاياها أنها تستطيع أن تحول ملف JPEG موجوداً إلى JPEG XL دون أي فقد ثم تعيده كما كان بايتاً ببايت، وهذا مهم لمن عنده أرشيف كبير من الصور. وقصة دعمها في المتصفحات طويلة، والوضع بحسب [caniuse](https://caniuse.com/jpegxl?ref=arabroot.io) في أكتوبر 2026: مدعومة في Chrome لسطح المكتب منذ الإصدار 155، وفي Firefox منذ 158، ودعم جزئي في Safari منذ الإصدار 17 للصور الثابتة دون الحركة ودون العرض التدريجي، وغير مدعومة في Edge ولا في Chrome لنظام Android ولا في Samsung Internet. ولذلك إذا استخدمتها فضعها دائماً داخل وسم `picture` مع بديل، كما سوف نرى في أفضل الممارسات.

### HEIC

HEIC هي صورة مضغوطة بترميز الفيديو HEVC أي H.265 داخل حاوية HEIF، وهي الصيغة التي تحفظ بها هواتف iPhone الصور افتراضياً. ومشكلتها على الويب في الرخص قبل التقنية، فترميز HEVC تغطيه براءات اختراع ترخص عبر مجمعات براءات Patent Pools مثل [Access Advance](https://accessadvance.com/?ref=arabroot.io) و[Via LA](https://www.via-la.com/?ref=arabroot.io)، وقد شرحنا ذلك في [قسم الرخص في مقال الفيديو](https://arabroot.io/articles/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#licensing)، ولهذا السبب لا يدعمها بحسب [caniuse](https://caniuse.com/heif?ref=arabroot.io) إلا Safari منذ الإصدار 17\. والنتيجة العملية: إذا رفع المستخدمون صوراً من هواتفهم إلى تطبيقك فاقبل HEIC وحولها على السيرفر إلى JPEG أو WebP أو AVIF قبل عرضها، والمكتبة المفتوحة لقراءتها هي [libheif](https://github.com/strukturag/libheif?ref=arabroot.io).

والجدول التالي يلخص دعم المتصفحات بحسب caniuse في أكتوبر 2026:

| الصيغة                                                | Chrome وEdge                         | Firefox     | Safari         | الخلاصة العملية                           |
| ----------------------------------------------------- | ------------------------------------ | ----------- | -------------- | ----------------------------------------- |
| JPEG وPNG وGIF                                        | نعم                                  | نعم         | نعم            | تعمل في كل مكان، وهي البديل الأخير دائماً |
| [WebP](https://caniuse.com/webp?ref=arabroot.io)      | نعم                                  | نعم منذ 65  | نعم منذ 16     | آمنة للاستخدام مباشرة اليوم               |
| [AVIF](https://caniuse.com/avif?ref=arabroot.io)      | Chrome منذ 85، وEdge منذ 121         | نعم منذ 93  | كاملة منذ 16.4 | آمنة، مع بديل للأجهزة القديمة             |
| [JPEG XL](https://caniuse.com/jpegxl?ref=arabroot.io) | Chrome لسطح المكتب منذ 155، وEdge لا | نعم منذ 158 | جزئي منذ 17    | دائماً مع بديل                            |
| [HEIC](https://caniuse.com/heif?ref=arabroot.io)      | لا                                   | لا          | نعم منذ 17     | لا تعرضها على الويب، حولها                |

## SVG: الصورة التي هي كود، وخطر XSS

ملف [SVG](https://www.w3.org/TR/SVG2/?ref=arabroot.io) هو ملف XML نصي يصف الأشكال، ولذلك تفتحه في أي محرر نصوص، وتستطيع أن تغير لونه بـ CSS، ويضغطه gzip أو Brotli جيداً عند الإرسال. ولكن لاحظ أن كونه كوداً هو بالضبط مصدر خطره، فملف SVG يستطيع أن يحمل وسم `<script>` أو معالج أحداث مثل `onload`، فإذا سمح تطبيقك للمستخدمين برفع صور SVG ثم عرضها على نطاقك نفسه، وفتح أحدهم رابط الملف مباشرة، فإن السكربت يعمل داخل موقعك بصلاحيات الزائر، وهذه ثغرة Stored XSS كاملة.

والتفصيل الذي يجب أن تعرفه هو أن المتصفح لا يشغل السكربتات عندما يعرض SVG داخل وسم `<img>` أو كخلفية CSS، كما يوضح [توثيق MDN عن SVG كصورة](https://developer.mozilla.org/en-US/docs/Web/SVG/Guides/SVG%5Fas%5Fan%5Fimage?ref=arabroot.io)، ولكنه يشغلها عندما يفتح الملف وحده في الصفحة أو يضمن بـ `<object>` أو `<iframe>`. ولذلك فالحماية عدة طبقات:

- لا تقبل SVG من المستخدمين إلا إذا احتجت إليه فعلاً، وإذا قبلته فنظفه Sanitize بمكتبة معروفة، أو حوله على السيرفر إلى PNG أو WebP، فلا يبقى فيه أي كود.
- قدم الملفات المرفوعة من نطاق منفصل عن تطبيقك، ومع ترويسة `Content-Security-Policy` تمنع السكربتات، و`X-Content-Type-Options: nosniff`، وقد شرحناهما في [مقال ترويسات الأمان](https://arabroot.io/articles/%D8%AA%D8%B1%D9%88%D9%8A%D8%B3%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%86-hsts-%D9%88-csp/#csp).
- تحقق من نوع الملف من محتواه وليس من امتداده، كما في [قسم رفع الملفات في مقال البرمجة الآمنة](https://arabroot.io/articles/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A7%D9%85%D9%86%D8%A9-secure-coding-%D9%84%D9%84%D9%85%D8%B7%D9%88%D8%B1%D9%8A%D9%86/#uploads)، وفي [دليل OWASP لرفع الملفات](https://cheatsheetseries.owasp.org/cheatsheets/File%5FUpload%5FCheat%5FSheet.html?ref=arabroot.io).

## أيقونة الموقع Favicon وصيغة ICO

الأيقونة الصغيرة في تبويب المتصفح لها تاريخ خاص، فصيغة [ICO](https://learn.microsoft.com/en-us/previous-versions/ms997538%28v=msdn.10%29?ref=arabroot.io) من Microsoft هي ملف واحد يحمل عدة أحجام من نفس الأيقونة، مثل 16 و32 و48 بكسل، والمتصفحات تبحث افتراضياً عن `/favicon.ico` في المسار الرئيسي للموقع. أما اليوم فتستطيع أن تحدد الأيقونة صراحة بوسم `<link rel="icon">` كما في [توثيق MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel?ref=arabroot.io#icon)، والمجموعة المعتادة: أيقونة SVG واحدة للمتصفحات الحديثة، وملف `favicon.ico` للقديمة، وصورة PNG بمقاس 180 لشاشة iPhone الرئيسية:

```html
<link rel="icon" href="/favicon.ico" sizes="32x32">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
```

## البيانات الوصفية Metadata: ماذا تقول الصورة عنك؟

الملف لا يحمل البكسلات فقط، فالكاميرا والهاتف يضيفان بيانات EXIF مثل نوع الجهاز ووقت التصوير وإعدادات العدسة، وكثيراً ما يضيفان الموقع الجغرافي بالضبط، وبرامج التحرير تضيف بيانات XMP وIPTC مثل اسم المصور وحقوق النشر، وقد رأينا في [تجربة سيارات مسح الخرائط](https://arabroot.io/articles/%D8%B3%D9%8A%D8%A7%D8%B1%D8%A7%D8%AA-%D9%85%D8%B3%D8%AD-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-%D9%85%D8%A7%D8%B0%D8%A7-%D8%AA%D8%AC%D9%85%D8%B9-%D9%88%D8%A7%D9%8A-%D8%B9%D8%AA%D8%A7%D8%AF-%D8%AA%D8%AD%D9%85%D9%84/#lab-exif) كيف يقرأ `exiftool` خط العرض وخط الطول واتجاه الكاميرا من صورة هاتف. ولهذا السبب فإن حذف البيانات الوصفية قبل النشر قاعدة خصوصية قبل أن يكون توفيراً في الحجم، وفي التجربة سوف نرى أن هذه البيانات أخذت وحدها 20 KB من صورة الويب، أي أكثر من 13% من حجمها.

⚠️

إذا كان تطبيقك يقبل صوراً من المستخدمين، فاحذف بيانات EXIF على السيرفر قبل نشر الصورة، ولا تعتمد على أن الهاتف حذفها، والسبب أن بعض التطبيقات تحذف الموقع وبعضها لا، والمستخدم لا يعرف أن صورة بيته تحمل إحداثياته. وانتبه إلى أن حذف كل البيانات يحذف معها اتجاه الصورة Orientation وملف الألوان، فطبق الاتجاه على البكسلات وحول الألوان إلى sRGB أولاً، ثم احذف الباقي، وهذا ما تفعله الأوامر في التجربة.

## التجربة العملية: نفس الصورة بكل الصيغ

حتى لا نكتفي بالكلام، أخذنا صورتين مختلفتين تماماً وضغطناهما بكل الصيغ. الأولى صورة الغروب التي التقطها [مصور NASA في مركز كينيدي للفضاء](https://images.nasa.gov/details/KSC-20180621-PH%5FKLS01%5F0091?ref=arabroot.io) في 21 يونيو 2018، وصور NASA في الملكية العامة بحسب [إرشادات استخدام وسائطها](https://www.nasa.gov/nasa-brand-center/images-and-media/?ref=arabroot.io)، والثانية رسم من رسوماتنا، وهو رسم Base64 من [مقال الترميز](https://arabroot.io/articles/%D8%A7%D9%84%D8%AA%D8%B1%D9%85%D9%8A%D8%B2-base64-%D9%88-base32-%D9%88-base58/#base64)، صورناه بالمتصفح كملف PNG دون فقد. ثم شعار عرب رووت بصيغة SVG. والأدوات كلها مكتبات مفتوحة المصدر من Debian داخل Container واحد: [libvips](https://www.libvips.org/API/current/?ref=arabroot.io) وImageMagick وcwebp وavifenc وcjxl، و[ExifTool](https://exiftool.org/?ref=arabroot.io).

💡

الأحجام في هذه التجربة خاصة بهاتين الصورتين وبإصدارات الأدوات المذكورة، فصورة أخرى قد تعطي ترتيباً مختلفاً قليلاً، وأوقات الترميز خاصة بجهازنا. الفكرة أن ترى الطريقة وتطبقها على صورك أنت.

### تجهيز الأدوات والصور

نشغل Container من Python 3.13 بإصدار مثبت، ونثبت فيه الأدوات من مستودع Debian 13، ثم ننزل الصورة الأصلية:

```bash
docker run -d --name lab-img-tools python:3.13.16-slim sleep infinity
docker exec lab-img-tools bash -c "apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends \
  libvips-tools imagemagick webp libavif-bin libjxl-tools libimage-exiftool-perl brotli curl ca-certificates"
docker exec lab-img-tools bash -c "mkdir -p /lab && cd /lab && curl -sSfo nasa-orig.jpg \
  https://images-assets.nasa.gov/image/KSC-20180621-PH_KLS01_0091/KSC-20180621-PH_KLS01_0091~orig.JPG && \
  exiftool -Make -Model -ImageSize -Artist -ProfileDescription nasa-orig.jpg && ls -l nasa-orig.jpg"
```

والمخرج سوف يكون كما يلي:

```text
Make                            : Canon
Camera Model Name               : Canon EOS 5D Mark IV
Image Size                      : 4480x6720
Artist                          : NASA/Kim Shiflett
Profile Description             : Adobe RGB (1998)
-rw-r--r-- 1 root root 17827020 Oct  9 01:33 nasa-orig.jpg
```

لاحظ أن الصورة الأصلية بدقة 4480 × 6720 وحجمها 17.8 MB، وفضاء ألوانها Adobe RGB وليس sRGB. والآن نصغرها إلى عرض 1200 بكسل، وهو عرض معقول لصورة في مقال، ونحول ألوانها إلى sRGB، ونحفظها PNG دون فقد لتكون الأصل الذي نقارن به كل الصيغ، ثم ننسخ إلى ال Container لقطة الرسم والشعار، وتستطيع أن تضع مكانهما أي لقطة شاشة PNG وأي شعار SVG لديك:

```bash
docker exec lab-img-tools bash -c "cd /lab && vipsthumbnail nasa-orig.jpg -s 1200x --export-profile srgb -o photo.png && vipsheader photo.png"
docker cp screenshot.png lab-img-tools:/lab/screenshot.png
docker cp arabroot-english-brand.svg lab-img-tools:/lab/logo.svg
```

```text
photo.png: 1200x1800 uchar, 3 bands, srgb, pngload
```

### الصورة الفوتوغرافية: أصغر ملف بنفس الجودة

المقارنة الصحيحة بين الصيغ ليست بنفس رقم الجودة، فالرقم 80 في JPEG لا يعني نفس الشيء في WebP أو AVIF، وإنما بنفس الجودة المقاسة. لذلك كتبنا سكربت يبدأ من جودة منخفضة في كل أداة ويرفعها خطوة خطوة، ويفك كل ملف ويقيس SSIM مع الأصل بأداة [compare من ImageMagick](https://imagemagick.org/script/compare.php?ref=arabroot.io)، ويتوقف عند أول ملف يصل إلى الحد المطلوب:

```bash
#!/bin/bash
# match.sh <ref.png> <target-ssim> : for each lossy encoder, the smallest file whose SSIM >= target
ref=$1; T=$2; w=/lab/m-${ref%.png}; mkdir -p $w; cd $w
ssim() { magick compare -metric SSIM /lab/$ref "$1" null: 2>&1; }
ok() { awk -v a="$1" -v t="$T" 'BEGIN{exit !(a>=t)}'; }
best() { echo "$1 $2 bytes=$3 ssim=$4"; }
for q in $(seq 40 1 98); do vips jpegsave /lab/$ref j.jpg --Q $q --optimize-coding --strip; vips copy j.jpg d.png; s=$(ssim d.png); if ok $s; then best jpeg "q=$q" $(stat -c%s j.jpg) $s; cp j.jpg out.jpg; break; fi; done
for q in $(seq 40 1 99); do cwebp -quiet -q $q -m 6 /lab/$ref -o w.webp; dwebp -quiet w.webp -o d.png; s=$(ssim d.png); if ok $s; then best webp "q=$q" $(stat -c%s w.webp) $s; cp w.webp out.webp; break; fi; done
for q in $(seq 30 2 98); do avifenc -q $q -s 6 /lab/$ref a.avif >/dev/null; avifdec a.avif d.png >/dev/null; s=$(ssim d.png); if ok $s; then best avif "q=$q" $(stat -c%s a.avif) $s; cp a.avif out.avif; break; fi; done
for d in 4.0 3.5 3.0 2.8 2.6 2.4 2.2 2.0 1.9 1.8 1.7 1.6 1.5 1.4 1.3 1.2 1.1 1.0 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1; do cjxl --quiet -d $d -e 7 /lab/$ref x.jxl 2>/dev/null; djxl --quiet x.jxl d.png 2>/dev/null; s=$(ssim d.png); if ok $s; then best jxl "d=$d" $(stat -c%s x.jxl) $s; cp x.jxl out.jxl; break; fi; done
```

نحفظ السكربت باسم `match.sh` وننسخه إلى ال Container، ثم نشغله على صورة الغروب بحد SSIM يساوي 0.955، وهو قريب مما يعطيه JPEG بالجودة 77:

```bash
docker cp match.sh lab-img-tools:/lab/match.sh
docker exec lab-img-tools bash -c "cd /lab && bash match.sh photo.png 0.955"
```

والمخرج سوف يكون كما يلي:

```text
jpeg q=77 bytes=119715 ssim=0.956044
webp q=85 bytes=85910 ssim=0.955129
avif q=62 bytes=67539 ssim=0.956047
jxl d=2.0 bytes=83037 ssim=0.956147
```

في المخرج أعلاه لاحظ التالي:

- الأربعة وصلت إلى نفس الجودة تقريباً، والفرق في الحجم فقط: AVIF أصغر من JPEG بنحو 44%، وJPEG XL بنحو 31%، وWebP بنحو 28%.
- رقم الجودة الذي احتاجته كل أداة مختلف تماماً: 77 في JPEG و85 في WebP و62 في AVIF، وهذا هو السبب في أن مقارنة الصيغ بنفس الرقم مضللة.
- في JPEG XL لا يوجد رقم جودة من 0 إلى 100، وإنما المسافة Distance، حيث 1.0 تعني فرقاً لا تلاحظه العين تقريباً في الظروف العادية، ونحتاج هنا 2.0.
- لم نستخدم أي أداة تحسين خاصة مثل mozjpeg، فقيم JPEG من libvips مع تحسين جداول Huffman، وأداة أفضل قد تقلل JPEG قليلاً.

وقد يتساءل البعض: وكم يكلف هذا التوفير من وقت المعالج؟ قسنا زمن ترميز صورة الغروب مرة واحدة بالإعدادات أعلاه على جهازنا، وهو معالج Intel Core i7-7700K، فكانت النتائج: JPEG في 0.62 ثانية، وWebP في 1.16، وAVIF في 1.64، وJPEG XL في 2.5 ثانية، والأرقام تشمل تشغيل كل أداة وقراءة الملف. وهذا فرق لا يهم إذا حولت الصورة مرة واحدة عند الرفع، ولكنه يهم إذا كنت تحولها عند كل طلب دون Cache.

### الرسم ولقطة الشاشة: دون فقد

الآن نفس السؤال مع الرسم، وهو 1400 × 752 بكسل فيه نص وألوان مسطحة، ومعه صيغة GIF وPNG بلوحة 256 لوناً لصورة الغروب أيضاً. السكربت التالي يحفظ الصورة بكل صيغة دون فقد، ثم بلوحة ألوان، ويقيس SSIM للصيغتين اللتين تفقدان الألوان:

```bash
#!/bin/bash
# lossless.sh <ref.png> : lossless sizes, plus GIF and 256-colour PNG (palette) with their SSIM
ref=$1; w=/lab/l-${ref%.png}; mkdir -p $w; cd $w
ssim() { magick compare -metric SSIM /lab/$ref "$1" null: 2>&1; }
vips pngsave /lab/$ref p.png --compression 9 --strip;          echo "png-truecolour bytes=$(stat -c%s p.png)"
cwebp -quiet -lossless -z 9 /lab/$ref -o w.webp;               echo "webp-lossless bytes=$(stat -c%s w.webp)"
avifenc -l -s 6 /lab/$ref a.avif >/dev/null;                   echo "avif-lossless bytes=$(stat -c%s a.avif)"
cjxl --quiet -d 0 -e 7 /lab/$ref x.jxl 2>/dev/null;            echo "jxl-lossless bytes=$(stat -c%s x.jxl)"
vips pngsave /lab/$ref p8.png --palette --compression 9 --strip; s=$(ssim p8.png); echo "png-palette-256 bytes=$(stat -c%s p8.png) ssim=$s"
magick /lab/$ref g.gif; magick g.gif d.png; echo "gif bytes=$(stat -c%s g.gif) ssim=$(ssim d.png)"
```

```bash
docker cp lossless.sh lab-img-tools:/lab/lossless.sh
docker exec lab-img-tools bash -c "cd /lab && bash lossless.sh photo.png; echo ---; bash lossless.sh screenshot.png; echo ---; bash match.sh screenshot.png 0.99"
```

والمخرج سوف يكون كما يلي:

```text
png-truecolour bytes=2748863
webp-lossless bytes=1842700
avif-lossless bytes=2441826
jxl-lossless bytes=1847846
png-palette-256 bytes=812667 ssim=0.975427
gif bytes=728270 ssim=0.955822
---
png-truecolour bytes=59243
webp-lossless bytes=38124
avif-lossless bytes=153992
jxl-lossless bytes=81595
png-palette-256 bytes=33630 ssim=0.999685
gif bytes=56145 ssim=0.998465
---
jpeg q=90 bytes=178898 ssim=0.991452
webp q=91 bytes=73896 ssim=0.99007
avif q=32 bytes=19707 ssim=0.990037
jxl d=4.0 bytes=53875 ssim=0.99148
```

ثم شغلنا JPEG XL بأعلى جهد على الرسم، لأن الإعداد `-e 7` الافتراضي لم يكن أفضل ما لديه:

```bash
docker exec lab-img-tools bash -c "cd /lab && mkdir -p x && cjxl --quiet -d 0 -e 9 screenshot.png x/s9.jxl 2>/dev/null; stat -c%s x/s9.jxl"
```

```text
74564
```

في المخرج أعلاه لاحظ التالي:

- PNG لصورة الغروب 2.75 MB، أي 23 ضعف JPEG بنفس الجودة تقريباً، وحتى أفضل صيغة دون فقد هنا، WebP، كانت 1.84 MB، فالضغط دون فقد للصور الفوتوغرافية لا يناسب الويب.
- مع الرسم انقلبت النتيجة: PNG بلوحة 256 لوناً كانت أصغر ملف، 33.6 KB بتشابه 0.9997، ثم WebP دون فقد 38.1 KB، والاثنان أصغر من JPEG بالجودة 90 خمس مرات تقريباً، ودون أي تشويه.
- AVIF دون فقد كان أسوأ صيغة للرسم، وأكبر من WebP وJPEG XL لصورة الغروب، فإذا احتجت صورة دون فقد فلا تختر AVIF.
- AVIF مع الفقد وصل للرسم إلى 19.7 KB بـ SSIM يساوي 0.99، وهو رقم مغر، ولكن SSIM لا يرى دائماً تشوه حواف الحروف الصغيرة، فقبل أن تعتمد ضغطاً مع الفقد لصور فيها نص، انظر إليها بعينك بتكبير 200%.
- GIF لصورة الغروب أعطى 728 KB بـ SSIM يساوي 0.956، أي ستة أضعاف JPEG بنفس التشابه، ومع نقاط Dithering واضحة كما في الصورة التالية.

والصورة التالية تجمع الأحجام في رسمين، كل رسم بمقياسه:

![رسمان بيانيان أفقيان: على اليمين صورة الغروب بنفس SSIM 0.955 حيث AVIF 67.5 KB وJPEG XL 83 KB وWebP 85.9 KB وJPEG 119.7 KB، وتحتها GIF 728.3 KB وPNG 2,748.9 KB للمقارنة، وعلى اليسار الرسم حيث PNG بلوحة ألوان 33.6 KB وWebP دون فقد 38.1 KB وPNG 59.2 KB وJPEG XL دون فقد 74.6 KB وAVIF دون فقد 154 KB وJPEG بالجودة 90 بحجم 178.9 KB](https://arabroot.io/content/images/2026/10/image-formats-04-lab-sizes.webp)

الصيغة الأفضل للصورة الفوتوغرافية ليست الأفضل للرسم، والعكس صحيح

والأرقام وحدها لا تكفي، فالصورة التالية مقصوصة من ملفات التجربة نفسها ومكبرة دون تنعيم:

![أربعة مربعات: جزء من صورة الغروب الأصلية بجانبه نفس الجزء من ملف GIF وفيه نقاط واضحة في السماء، ثم جزء من الرسم الأصلي بالنص البرتقالي 0x52 بجانبه نفس الجزء من JPEG بالجودة 90 مع 4:2:0 والحواف الملونة مشوشة](https://arabroot.io/content/images/2026/10/image-formats-05-lab-crops.webp)

GIF يملأ التدرج بالنقاط، وJPEG يشوش حواف النص الملون حتى بالجودة 90

### خيارات JPEG: تقليل الألوان والعرض التدريجي

نرى الآن أثر 4:2:0 على الرسم بالأرقام، ثم أثر العرض التدريجي Progressive على صورة الغروب:

```bash
cd /lab/x
for m in on off; do
  vips jpegsave ../screenshot.png s-$m.jpg --Q 90 --optimize-coding --strip --subsample-mode $m
  vips copy s-$m.jpg d-$m.png
  echo jpeg-q90-subsample-$m $(stat -c%s s-$m.jpg) $(magick compare -metric SSIM ../screenshot.png d-$m.png null: 2>&1)
done
vips jpegsave ../photo.png base.jpg --Q 77 --optimize-coding --strip
vips jpegsave ../photo.png prog.jpg --Q 77 --optimize-coding --strip --interlace
echo photo-baseline $(stat -c%s base.jpg) progressive $(stat -c%s prog.jpg)
vipsheader -f jpeg-chroma-subsample base.jpg
vipsheader -f jpeg-chroma-subsample s-off.jpg
```

والمخرج سوف يكون كما يلي:

```text
jpeg-q90-subsample-on 124659 0.984302
jpeg-q90-subsample-off 178898 0.991452
photo-baseline 119715 progressive 119040
4:2:0
4:4:4
```

في المخرج أعلاه لاحظ التالي:

- تقليل الألوان وفر 30% من حجم الرسم، ولكنه أنزل SSIM من 0.991 إلى 0.984، وهذا هو التشويش الذي رأيته في الصورة السابقة.
- libvips تختار الوضع تلقائياً: الصورة بالجودة 77 حفظت بـ 4:2:0، والجودة 90 في السكربت الأول حفظت بـ 4:4:4 دون أن نطلب ذلك، ولهذا تطابق حجمها مع `subsample-mode off`، فاعرف ما تفعله أداتك افتراضياً قبل أن تقارن.
- JPEG التدريجي كان أصغر بـ 675 بايت فقط، فميزته الأساسية في طريقة الظهور أثناء التنزيل وليست في الحجم.

### الشعار: SVG مقابل PNG

الشعار مرسوم بالأشكال، فالمقارنة هنا بين ملف SVG واحد وبين نسخ PNG بالمقاسات التي تحتاجها الشاشات العادية والكثيفة، أي 1x و2x و3x:

```bash
cd /lab && mkdir -p svg && cd svg && cp ../logo.svg .
echo svg $(stat -c%s logo.svg) gzip-9 $(gzip -9 -c logo.svg | wc -c) brotli $(brotli -c -q 11 logo.svg | wc -c)
for s in 1 2 3; do
  vips copy "../logo.svg[scale=$s]" l$s.png
  vips pngsave l$s.png p$s.png --compression 9 --strip
  vips pngsave l$s.png q$s.png --palette --compression 9 --strip
  cwebp -quiet -lossless -z 9 l$s.png -o w$s.webp
  echo scale=$s $(vipsheader l$s.png | cut -d' ' -f2) png=$(stat -c%s p$s.png) png8=$(stat -c%s q$s.png) webp-ll=$(stat -c%s w$s.webp)
done
```

والمخرج سوف يكون كما يلي:

```text
svg 41513 gzip-9 10426 brotli 8808
scale=1 842x176 png=15707 png8=9185 webp-ll=8868
scale=2 1683x352 png=35784 png8=18193 webp-ll=17036
scale=3 2525x528 png=59022 png8=28084 webp-ll=25588
```

الملف الأصلي 41.5 KB يبدو كبيراً أمام PNG بمقاس 1x، ولكن لاحظ أن المتصفح يستقبله مضغوطاً بـ Brotli أي 8.8 KB، وهو ملف واحد يغني عن ثلاثة مقاسات، ولا يتشوه في أي تكبير. وعندما فتحنا الملف وجدنا أن الإحداثيات فيه مكتوبة بـ 16 خانة عشرية، مثل `282.0,0.4264184847821184`، وهذه دقة لا تراها أي شاشة، فقربناها إلى خانة عشرية واحدة داخل مسارات الرسم فقط، ثم قارنا الرسم الناتج بالأصل:

```bash
python3 -c "
import re;s=open('logo.svg').read()
o=re.sub(r'd=\"[^\"]*\"',lambda m:re.sub(r'(\d+\.\d)\d+',r'\1',m.group(0)),s);open('logo-1dp.svg','w').write(o)"
echo 1dp $(stat -c%s logo-1dp.svg) gzip $(gzip -9 -c logo-1dp.svg|wc -c) brotli $(brotli -c -q 11 logo-1dp.svg|wc -c)
vips copy logo.svg[scale=2] r0.png; vips copy logo-1dp.svg[scale=2] r1.png
magick r0.png -background white -flatten f0.png; magick r1.png -background white -flatten f1.png
magick compare -metric SSIM f0.png f1.png null:; echo
```

```text
1dp 16510 gzip 6407 brotli 5078
0.999823
```

أي أن الملف نزل من 41.5 KB إلى 16.5 KB، وبعد Brotli إلى 5 KB، والفرق في الرسم لا تراه العين، وهذا بالضبط ما تفعله أدوات تحسين SVG. ويجدر الإشارة هنا إلى أن التقريب يجب ألا يلمس أرقام التحويل، مثل رقم التكبير `scale(0.30531813)` في وسم المجموعة، فإذا أصبح `scale(0.3)` تغير حجم الشعار كله ونزل SSIM إلى نحو 0.79، ولهذا يقتصر التقريب في الأمر أعلاه على مسارات الرسم داخل `d="…"`.

### البيانات الوصفية وكم تأخذ من الحجم

أخيراً نصغر الصورة الأصلية مرتين، مرة مع حذف البيانات الوصفية ومرة دون حذفها، ونرى ما بقي في كل ملف:

```bash
cd /lab
vipsthumbnail nasa-orig.jpg -s 1200x --export-profile srgb -o web.jpg[Q=77,strip]
exiftool -s -Make -Model -Artist -ProfileDescription web.jpg; ls -l web.jpg
vipsthumbnail nasa-orig.jpg -s 1200x --export-profile srgb -o web-keep.jpg[Q=77]
exiftool -s -Make -Model -ProfileDescription web-keep.jpg; ls -l web-keep.jpg
vipsheader -a web-keep.jpg | grep -E 'bytes of binary'
```

والمخرج سوف يكون كما يلي:

```text
-rw-r--r-- 1 root root 132487 Oct  9 13:34 web.jpg
Make                            : Canon
Model                           : Canon EOS 5D Mark IV
ProfileDescription              : sRGB
-rw-r--r-- 1 root root 152874 Oct  9 13:34 web-keep.jpg
exif-data: 3598 bytes of binary data
jpeg-thumbnail-data: 2396 bytes of binary data
xmp-data: 10930 bytes of binary data
iptc-data: 5320 bytes of binary data
icc-profile-data: 480 bytes of binary data
```

الملف الأول لم يطبع `exiftool` له أي حقل لأنه لم يبق فيه شيء، والثاني احتفظ بنوع الكاميرا وببيانات XMP وIPTC وصورة مصغرة مدمجة، والفرق بينهما 20,387 بايت، أي 13% من حجم الصورة دون أي فائدة للزائر. ولاحظ أن `--export-profile srgb` حول الألوان من Adobe RGB قبل الحذف، فبقيت الألوان صحيحة في الملف المحذوف منه كل شيء، لأن المتصفح يفترض sRGB.

### حذف التجربة

```bash
docker rm -f lab-img-tools
```

## كيف تختار الصيغة؟

بعد كل ما سبق، القرار يبدأ من نوع المحتوى وليس من الصيغة الأحدث، والصورة التالية تلخصه:

![مخطط قرار يبدأ بسؤال ما الذي في الصورة، وخمسة فروع: الشعار والأيقونة والرسم البياني إلى SVG وإلا PNG أو WebP، والصورة الفوتوغرافية إلى AVIF أو WebP وإلا JPEG، ولقطة الشاشة والنص إلى PNG أو WebP دون فقد وإلا PNG بلوحة ألوان، والحركة إلى فيديو MP4 أو WebM وإلا WebP أو AVIF متحرك، وأيقونة الموقع إلى SVG وإلا ICO مع PNG 180](https://arabroot.io/content/images/2026/10/image-formats-07-decision.webp)

ابدأ من سؤال: ما الذي في الصورة؟

| المحتوى                  | الصيغة الأولى                     | البديل                     | لا تستخدم           |
| ------------------------ | --------------------------------- | -------------------------- | ------------------- |
| صورة فوتوغرافية          | AVIF أو WebP مع الفقد             | JPEG                       | PNG وGIF            |
| لقطة شاشة، واجهة، نص     | PNG أو WebP دون فقد               | PNG بلوحة 256 لوناً        | JPEG                |
| شعار، أيقونة، رسم بياني  | SVG                               | PNG أو WebP بمقاسات 1x و2x | JPEG                |
| صورة فيها شفافية         | WebP أو AVIF                      | PNG                        | JPEG، فهو لا يدعمها |
| حركة                     | فيديو MP4 أو WebM                 | WebP أو AVIF متحرك         | GIF للمقاطع الطويلة |
| صور المستخدمين من الهاتف | استقبل أي صيغة وحولها على السيرفر |                            | عرض HEIC مباشرة     |

## أفضل الممارسات على الويب

### الصور المتجاوبة: srcset وsizes ووسم picture

الحل البسيط هو أن تضع صورة واحدة بعرض 1600 بكسل لكل الزوار، والمشكلة أن هاتفاً عرضه 390 بكسل سوف ينزل بايتات لن يعرضها، بينما شاشة كثيفة البكسلات تحتاج أكثر من عرضها الظاهري. والطريقة الصحيحة أن تجهز عدة مقاسات وعدة صيغ، وتصف للمتصفح متى يحتاج كل مقاس، وهو يختار، كما يشرح [دليل MDN للصور المتجاوبة](https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Responsive%5Fimages?ref=arabroot.io):

```html
<picture>
  <source type="image/avif"
          srcset="sunset-800.avif 800w, sunset-1200.avif 1200w, sunset-1600.avif 1600w"
          sizes="(max-width: 700px) 100vw, 50vw">
  <source type="image/webp"
          srcset="sunset-800.webp 800w, sunset-1200.webp 1200w, sunset-1600.webp 1600w"
          sizes="(max-width: 700px) 100vw, 50vw">
  <img src="sunset-1200.jpg"
       srcset="sunset-800.jpg 800w, sunset-1200.jpg 1200w, sunset-1600.jpg 1600w"
       sizes="(max-width: 700px) 100vw, 50vw"
       width="1200" height="1800" loading="lazy" decoding="async"
       alt="غروب الشمس فوق بحيرة في فلوريدا">
</picture>
```

في الإعداد أعلاه لاحظ التالي:

- وسم [picture](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/picture?ref=arabroot.io) يجرب الوسوم `source` بالترتيب ويأخذ أول نوع يعرفه، فإذا لم يعرف AVIF ولا WebP استخدم `img` مع JPEG، ولذلك ضع الصيغة الأكفأ أولاً.
- `srcset` يعدد الملفات وعرض كل منها بالبكسل الحقيقي، و`sizes` يقول للمتصفح كم سوف تأخذ الصورة من عرض الصفحة: كامل الشاشة في الشاشات الصغيرة ونصفها في غيرها، وهذا ما يحتاجه ليحسب قبل أن يعرف تنسيق الصفحة.
- `width` و`height` لا يحددان حجم العرض، وإنما يعطيان المتصفح نسبة الطول إلى العرض حتى يحجز المساحة قبل أن تنزل الصورة، فلا تقفز الصفحة تحت يد القارئ.
- `alt` يصف الصورة لمن لا يراها، ولقارئ الشاشة، ولمحركات البحث.

والصورة التالية تبين كيف يختار جهازان مختلفان من نفس الكود:

![على اليمين كود picture بثلاث صيغ وثلاثة مقاسات، وعلى اليسار هاتف عرضه 390 بكسل بكثافة 3 يحتاج 1170 بكسل فينزل ملف 1200، وحاسوب محمول عرضه 1440 بكسل بكثافة 1 والصورة نصف الشاشة أي 720 بكسل فينزل ملف 800](https://arabroot.io/content/images/2026/10/image-formats-06-responsive.webp)

أنت تصف الملفات والمساحة، والمتصفح يحسب الحاجة ويختار

### التحميل المؤجل Lazy Loading

الخاصية `loading="lazy"` في [وسم img](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img?ref=arabroot.io) تجعل المتصفح يؤجل تنزيل الصورة حتى يقترب القارئ منها، فلا تنافس صور أسفل المقال الصورة الأولى على الشبكة. ولكن لا تضعها على الصورة الكبيرة في أعلى الصفحة، والسبب أن المتصفح سوف ينتظر حتى يحسب التنسيق قبل أن يطلبها، فتتأخر أهم صورة في الصفحة، بل أعطها `fetchpriority="high"` بدلاً من ذلك.

### التصغير والتحويل عند الطلب

تجهيز ثلاث صيغ بثلاثة مقاسات لكل صورة يعني تسعة ملفات، وهذا مقبول لصور مقال تعرفها مسبقاً، فحولها مرة واحدة عند الرفع أو في خطوة البناء. أما إذا كانت الصور كثيرة ويرفعها المستخدمون، فالأنسب خدمة تستقبل الصورة الأصلية وتصغرها وتحول صيغتها عند الطلب حسب معاملات في الرابط وحسب ترويسة `Accept` التي يرسلها المتصفح، ثم تحفظ النتيجة في Cache. وقد ذكرنا في [مقال CDN](https://arabroot.io/articles/%D8%B4%D8%A8%D9%83%D8%A9-%D8%AA%D9%88%D8%B5%D9%8A%D9%84-%D8%A7%D9%84%D9%85%D8%AD%D8%AA%D9%88%D9%89-cdn-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#image-optimisation) أن بعض المزودين يقدمون ذلك على الحافة، وفي [مقال خدمات Cloudflare وبدائلها](https://arabroot.io/articles/%D8%AE%D8%AF%D9%85%D8%A7%D8%AA-cloudflare-%D9%88%D8%A8%D8%AF%D8%A7%D8%A6%D9%84%D9%87%D8%A7-%D9%85%D9%81%D8%AA%D9%88%D8%AD%D8%A9-%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1/) خدماتها للصور، ومن يريد تشغيله على سيرفره يستطيع أن يستخدم أداة مثل [imgproxy](https://www.imgproxy.net/?ref=arabroot.io)، وسوف نشرحها مقارنة ببدائلها في مقال قادم من [مرحلة معالجة الصور والمستندات](https://arabroot.io/start/#stage-special) بإذن الله.

### إعدادات ضغط تبدأ منها

بناء على التجربة، هذه نقطة بداية معقولة للصور الفوتوغرافية، ثم انظر إلى النتيجة بعينك وعدل:

- **JPEG:** جودة بين 75 و85 مع تحسين جداول Huffman، وتدريجي Progressive، واترك 4:2:0 للصور الفوتوغرافية.
- **WebP:** `cwebp -q 80` إلى `85` مع `-m 6` إذا كان وقت الترميز لا يهم.
- **AVIF:** `avifenc -q 55` إلى `65` مع `-s 6`، وقلل الرقم بعد `-s` إذا كنت تحول مرة واحدة وتريد ملفاً أصغر.
- **JPEG XL:** المسافة `-d 1.0` إلى `2.0`.
- **للرسوم ولقطات الشاشة:** PNG بلوحة ألوان إذا كانت الألوان قليلة، وإلا WebP دون فقد.
- **في كل الحالات:** صغر المقاس إلى ما تحتاجه الصفحة أولاً، فهذا وحده يوفر أكثر من أي إعداد جودة، واحذف البيانات الوصفية بعد تحويل الألوان إلى sRGB.

## أخطاء شائعة

1. **JPEG للقطات الشاشة:** ملف أكبر من PNG وحروف مشوشة في نفس الوقت، كما رأينا في التجربة.
2. **PNG للصور الفوتوغرافية:** 23 ضعف JPEG في صورتنا دون فرق تراه.
3. **GIF للمقاطع المتحركة:** استخدم فيديو قصيراً، وهو أصغر بكثير وأوضح.
4. **الصورة الأصلية كما هي:** رفع صورة الكاميرا بـ 17.8 MB ثم تصغيرها بـ CSS، فينزلها الزائر كاملة.
5. **مقارنة الصيغ بنفس رقم الجودة:** الرقم 80 يختلف معناه من أداة لأخرى، فقارن بالحجم عند نفس الجودة المقاسة.
6. **حذف ملف الألوان دون تحويل:** صورة Adobe RGB أو Display P3 تظهر باهتة إذا حذفت ICC Profile ولم تحولها إلى sRGB.
7. **عرض SVG من المستخدمين على نطاقك:** ثغرة XSS جاهزة، فنظفه أو حوله أو قدمه من نطاق منفصل.
8. **loading="lazy" على أول صورة في الصفحة:** يؤخر أهم صورة بدل أن يسرعها.
9. **نسيان width وheight:** تقفز الصفحة كلما نزلت صورة.

## تدريب عملي

- شغل `match.sh` على صورة من هاتفك بعد تصغيرها إلى 1200 بكسل، وقارن ترتيب الصيغ بترتيبها مع صورة الغروب. هل بقي AVIF الأصغر؟
- خذ لقطة شاشة لواجهة تطبيقك، واحفظها JPEG بالجودة 85 وPNG بلوحة ألوان وWebP دون فقد، ثم قارن الأحجام وانظر إلى النص بتكبير 300%.
- شغل `exiftool` على آخر صورة نشرتها في موقعك أو تطبيقك، وانظر هل بقي فيها نوع الجهاز أو الموقع.

## الخلاصة

وصلنا لنهاية الموضوع، وأهم ما فيه:

- الصورة النقطية تحفظ البكسلات، والمتجهة تحفظ الأشكال، فالشعارات والأيقونات والرسوم البيانية SVG، والصور الفوتوغرافية نقطية دائماً.
- الصورة الخام 3 بايتات لكل بكسل، أي 6.48 MB لصورة 1200 × 1800، والضغط مع الفقد وصل بها في تجربتنا إلى 67.5 KB في AVIF و119.7 KB في JPEG بنفس SSIM.
- للصور الفوتوغرافية AVIF أو WebP مع JPEG كبديل، وللقطات الشاشة والنص PNG أو WebP دون فقد، وللحركة فيديو قصير بدل GIF.
- JPEG XL مدعومة اليوم في Chrome لسطح المكتب وFirefox وجزئياً في Safari، وHEIC في Safari فقط، فاستخدمهما مع بديل أو حولهما على السيرفر.
- ملف SVG كود، فلا تعرض SVG من المستخدمين على نطاقك قبل تنظيفه، واحذف بيانات EXIF من صورهم قبل نشرها.
- على الويب: `picture` مع `srcset` و`sizes`، و`width` و`height` لكل صورة، و`loading="lazy"` لكل صورة إلا الأولى.

وفي هذه المرحلة نفسها شرحنا كيف يعمل الضغط من الداخل، وكيف تبنى ملفات الأرشيف مثل ZIP و7z:

[![](https://arabroot.io/content/images/2026/10/compression-basics-cover-cover.webp)دليلكيف يعمل ضغط البيانات Compression؟ من Huffman إلى Zstdلماذا تصغر ملفات السجلات إلى العشر ولا تصغر الصور أبداً، وكيف تختار أداة الضغط المناسبة بين السرعة والحجم.](https://arabroot.io/articles/%D9%83%D9%8A%D9%81-%D9%8A%D8%B9%D9%85%D9%84-%D8%B6%D8%BA%D8%B7-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-compression/)[![](https://arabroot.io/content/images/2026/10/zip-rar-inside-cover-cover.webp)دليلماذا يوجد داخل ملف ZIP، وما الذي يخفيه؟كيف يرتب ملف ZIP محتوياته من الداخل، ولماذا يستطيع ملف مضغوط صغير أن يملأ قرصك أو يكتب خارج المجلد الذي فككته فيه.](https://arabroot.io/articles/%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D9%88%D8%AC%D8%AF-%D8%AF%D8%A7%D8%AE%D9%84-%D9%85%D9%84%D9%81-zip/)[![](https://arabroot.io/content/images/2026/10/video-basics-cover-cover.webp)دليلمفاهيم الفيديو: الحاوية والترميز Codec ومعدل البتما الذي يحدد حجم ملف الفيديو وجودته، ولماذا يعمل ملف في متصفح ولا يعمل في آخر، مع تجربة حقيقية تقيس الفرق بين الترميزات.](https://arabroot.io/articles/%D9%85%D9%81%D8%A7%D9%87%D9%8A%D9%85-%D8%A7%D9%84%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/cdn-basics-cover-cover.webp)دليلكيف تعمل شبكة توصيل المحتوى CDN وما الذي تحفظهلماذا يبطؤ موقعك على الزائر البعيد، وكيف تقرب شبكة CDN ملفاتك منه، وكيف تمنعها من حفظ الصفحات الخاصة.](https://arabroot.io/articles/%D8%B4%D8%A8%D9%83%D8%A9-%D8%AA%D9%88%D8%B5%D9%8A%D9%84-%D8%A7%D9%84%D9%85%D8%AD%D8%AA%D9%88%D9%89-cdn-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)

## سجل التحديثات

- أكتوبر 2026: كتابة المقال، وتنفيذ التجربة على libvips 8.16.1 وImageMagick 7.1.1-43 وlibwebp 1.5.0 وlibavif 1.2.1 وlibjxl 0.11.2 من Debian 13.7، ودعم المتصفحات بحسب caniuse في أكتوبر 2026.