מפרט מאגר WebP

מבוא

WebP הוא פורמט תמונה שמשתמש (1) בקידוד של VP8 של מסגרת מפתח כדי לדחוס נתוני תמונה באופן 'lossy' או (2) בקידוד WebP ללא אובדן נתונים. שיטות הקידוד האלה אמורות להפוך את התהליך ליעיל יותר מאשר בפורמטים ישנים יותר, כמו JPEG,‏ GIF ו-PNG. הוא מותאם להעברה מהירה של תמונות ברשת (לדוגמה, לאתרים). לפורמט WebP יש מאפיינים זהים לפורמטים אחרים (פרופיל צבע, מטא-נתונים, אנימציה וכו'). במסמך הזה מתוארים המבנה והפרמטרים של קובץ WebP.

מאגר ה-WebP (כלומר מאגר ה-RIFF ל-WebP) מאפשר תמיכה בתכונות נוספות מעבר למקרה השימוש הבסיסי של WebP (כלומר קובץ שמכיל תמונה אחת בקידוד כפריים מפתח של VP8). הקונטיינר של WebP מספק תמיכה נוספת באפשרויות הבאות:

  • דחיסת lossless: אפשר לדחוס תמונה ללא אובדן נתונים באמצעות הפורמט WebP Lossless.

  • מטא-נתונים: יכול להיות שבתמונה יש מטא-נתונים שמאוחסנים בפורמט של קובץ תמונה להחלפה (Exif) או בפורמט של פלטפורמת מטא-נתונים נרחבת (XMP).

  • שקיפות: תמונה יכולה להיות שקופה, כלומר לכלול ערוץ אלפא.

  • פרופיל צבע: תמונה עשויה לכלול פרופיל ICC מוטמע כפי שמתואר על ידי International Color Consortium.

  • אנימציה: תמונה יכולה לכלול כמה פריימים עם השהיות, מה שהופך אותה לאנימציה.

מתן שמות

מומלץ להשתמש בסוגי ה-container הבאים כשמתייחסים ל-WebP:

שם הפורמט של הקונטיינרWebP
סיומת שם קובץ.webp
סוג MIMEimage/webp
מזהה סוג אחיד (UTI)org.webmproject.webp

מונחים ויסודות

מילות המפתח 'חובה', 'אסור', 'נדרש', 'חייב', 'אסור', 'צריך', 'אסור', 'מומלץ', 'לא מומלץ', 'יכול להיות' ו'אופציונלי' במסמך הזה צריכות להתפרש כפי שמתואר ב-BCP 14 RFC 2119 RFC 8174, כשהן מופיעות באותיות רישיות בלבד, כפי שמוצג כאן.

קובץ WebP מכיל תמונת סטילס (כלומר, מטריצה מקודדת של פיקסלים) או אנימציה. אפשר גם לכלול בו מידע על שקיפות, פרופיל צבע ומטא-נתונים. אנחנו מתייחסים למטריצת הפיקסלים בתור הקנבס של התמונה.

מספרי הביטים בתרשים הקטעים מתחילים ב-0 עבור הסיבית המשמעותית ביותר (MSB 0), כפי שמתואר ב-RFC 1166.

בהמשך מופיעים מונחים נוספים שמופיעים במסמך הזה:

קריאה/כתיבה
קוד שקורא קובצי WebP נקרא קורא, ואילו קוד שכותב אותם נקרא כותב.
uint16
מספר שלם ללא סימן באורך 16 ביט, בסדר קטן-גדול (little-endian).
uint24
מספר שלם ב-24 סיביות, ב-little-endian, ללא סימן.
uint32
מספר שלם לא חתום מסוג 32-bit.
FourCC
קוד בן ארבעה תווים (FourCC) הוא uint32 שנוצר על ידי שרשור של ארבעה תווים ASCII בסדר little-endian. המשמעות היא שהשדות 'aaaa' (0x61616161) ו-'AAAA' (0x41414141) נחשבים ל-FourCCs שונים.
בסיס 1
שדה של מספר שלם ללא סימן שמאחסן ערכים עם סטייה של -1. לדוגמה, בשדה כזה הערך 25 יישמר כ-24.
ChunkHeader('ABCD')
משמש לתיאור הכותרות FourCC ו-Chunk Size של קטעי קוד בודדים, כאשר 'ABCD' הוא ה-FourCC של קטע הקוד. הגודל של הרכיב הזה הוא 8 בייטים.

פורמט קובץ RIFF

פורמט הקובץ WebP מבוסס על פורמט המסמך RIFF (Resource Interchange File Format).

הרכיב הבסיסי של קובץ RIFF הוא מקטע. הוא מורכב מ:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Chunk FourCC                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          Chunk Size                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                         Chunk Payload                         :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chunk FourCC: ‏ 32 ביט
קוד ASCII בן ארבעה תווים המשמש לזיהוי מקטעים.
גודל קבוצת הנתונים: 32 סיביות (uint32)
הגודל של הקטע בבייטים, לא כולל את השדה הזה, מזהה הקטעים או המילוי.
המטען הייעודי של הקבוצה: Chunk Size בייטים
מטען הנתונים. אם הערך של Chunk Size הוא מספר אי-זוגי, מתווסף ביייט אחד של מילוי – שחייב להיות 0 כדי לעמוד בתקן RIFF.

הערה: ב-RIFF יש הסכמה לפיה קטעי FourCC באותיות רישיות גדולות הם קטעים רגילים שחלים על כל פורמט קובץ RIFF, ואילו קטעי FourCC ספציפיים לפורמט קובץ הם באותיות רישיות קטנות. קובצי WebP לא פועלים לפי המוסכמה הזו.

כותרת של קובץ WebP

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      'R'      |      'I'      |      'F'      |      'F'      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           File Size                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      'W'      |      'E'      |      'B'      |      'P'      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
'RIFF': 32 סיביות
תווי ה-ASCII 'R',‏ 'I',‏ 'F',‏ 'F'.
גודל הקובץ: 32 סיביות (uint32)
הגודל של הקובץ בבייטים, החל מההיסט 8. הערך המקסימלי של השדה הזה הוא 2^32 פחות 10 בייטים, ולכן גודל הקובץ כולו הוא לכל היותר 4GB פחות 2 בייטים.
'WEBP': 32 סיביות
תווי ASCII 'W', 'E', 'B', 'P'.

קובץ WebP חייב להתחיל בכותרת RIFF ב-F4CC 'WEBP'. גודל הקובץ בכותרת הוא הגודל הכולל של המקטעים הבאים, בתוספת 4 בייטים עבור ה-FourCC של 'WEBP'. אסור שהקובץ יכיל נתונים אחרי הנתונים שצוינו בגודל הקובץ. יכול להיות שהקוראים ינתחו קבצים כאלה ומתעלמים מהנתונים הסופיים. מכיוון שהגודל של כל מקטע הוא מספר זוגי, גם הגודל שמצוין בכותרת RIFF הוא מספר זוגי. התוכן של קטעים נפרדים מתואר בקטעים הבאים.

פורמט קובץ פשוט (אובדן נתונים)

צריך להשתמש בפריסה הזו אם התמונה מחייבת קידוד lossy ולא מחייבת שקיפות או תכונות מתקדמות אחרות שמסופקות על ידי הפורמט המורחב. קבצים בפריסה הזו קטנים יותר ותוכנות ישנות יותר תומכות בהם.

פורמט קובץ WebP פשוט (עם אובדן נתונים):

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                    WebP file header (12 bytes)                |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                        'VP8 ' Chunk                           :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

מקטע 'VP8 ':

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('VP8 ')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                           VP8 data                            :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
נתוני VP8: Chunk Size בייטים
נתוני מקור ביט של
VP8.

שימו לב שהתו הרביעי ב-FourCC של 'VP8 ' הוא רווח ASCII (0x20).

מפרט הפורמט של מקור הנתונים ב-VP8 מתואר במאמר מדריך לפורמט הנתונים ולפענוח של VP8. חשוב לזכור שכותרת הפריים של VP8 מכילה את רוחב הפריים ואת הגובה שלו. ההנחה היא שאלה רוחב הגובה של הקנבס.

במפרט של VP8 מתואר איך לפענח את התמונה לפורמט Y'CbCr. כדי להמיר ל-RGB, צריך להשתמש ב-Recommendation BT.601. יכול להיות שאפליקציות ישתמשו בשיטת המרה אחרת, אבל התוצאות החזוניות עשויות להיות שונות בין מקודדים.

פורמט קובץ פשוט (ללא אובדן נתונים)

הערה: יכול להיות שקוראים ישנים יותר לא תומכים בקבצים בפורמט lossless.

כדאי להשתמש בפריסה הזו אם התמונה דורשת קידוד ללא אובדן נתונים (עם ערוץ שקוף אופציונלי) ואין צורך בתכונות המתקדמות שסופקו על ידי הפורמט המורחב.

פורמט קובץ WebP פשוט (ללא אובדן נתונים):

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                    WebP file header (12 bytes)                |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                         'VP8L' Chunk                          :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

גוש 'VP8L':

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('VP8L')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                           VP8L data                           :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
נתוני VP8L: Chunk Size בייטים
נתוני bitstream של VP8L.

המפרט הנוכחי של מקור הנתונים (bitstream) של VP8L זמין במאמר פורמט מקור הנתונים (bitstream) ללא אובדן נתונים של WebP. חשוב לזכור שהכותרת של VP8L מכילה את רוחב התמונה ואת גובה התמונה של VP8L. ההנחה היא שהרוחב והגובה של הקנבס הם.

פורמט קובץ מורחב

הערה: יכול להיות שקוראים ישנים יותר לא תומכים בקבצים בפורמט המורחב.

קובץ בפורמט מורחב מורכב מ:

  • קבוצת 'VP8X' עם מידע על התכונות שבקובץ.

  • מקטע 'ICCP' אופציונלי עם פרופיל צבע.

  • מקטע אופציונלי של 'ANIM' עם נתוני פקדי אנימציה.

  • נתוני תמונה.

  • מקטע 'EXIF' אופציונלי עם מטא-נתונים של Exif.

  • מקטע 'XMP ' אופציונלי עם מטא-נתונים של XMP.

  • רשימה אופציונלית של מקטעים לא ידועים.

בתמונה סטילס, נתוני התמונה מורכבים מסגרת אחת, שמכילה את הרכיבים הבאים:

בתמונה מונפשת, נתוני התמונה מורכבים מכמה פריימים. פרטים נוספים על פריימים זמינים בקטע אנימציה.

כל הקטעים הנדרשים לשחזור ולתיקון הצבע, כלומר 'VP8X',‏ 'ICCP',‏ 'ANIM',‏ 'ANMF',‏ 'ALPH',‏ 'VP8 ' ו-'VP8L', חייבים להופיע בסדר שמתואר למעלה. הקוראים צריכים להיכשל אם המקטעים שרוצים לשחזר ולתיקון הצבע לא תקינים.

יכול להיות שמטא-נתונים וקטעים לא מוכרים יופיעו בסדר שגוי.

הסיבה: הקטעים הנדרשים לשחזור צריכים להופיע קודם בקובץ כדי לאפשר לקורא להתחיל לפענח תמונה לפני שהוא מקבל את כל הנתונים. שינוי הסדר של המטא-נתונים ומקטעי המקטעים בהתאמה אישית באפליקציה יכול להתאים להטמעה.

כותרת מורחבת של קובץ WebP:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                   WebP file header (12 bytes)                 |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('VP8X')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv|I|L|E|X|A|R|                   Reserved                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Canvas Width Minus One               |             ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
...  Canvas Height Minus One    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
שמורות (Rsv): 2 ביטים
חייב להיות 0. הקוראים חייבים להתעלם מהשדה הזה.
פרופיל ICC‏ (I): ביט אחד
מגדירים אם הקובץ מכיל גוש 'ICCP'.
אלפא (L): ביט אחד
הגדרה של אחד מהפריימים של התמונה שמכיל מידע על שקיפות ('אלפא').
מטא-נתונים של Exif‏ (E): ביט אחד
מגדירים את הערך הזה אם הקובץ מכיל מטא-נתונים של Exif.
מטא-נתונים של XMP‏ (X): ביט אחד
מגדירים אם הקובץ מכיל מטא-נתונים מסוג XMP.
אנימציה (A): ביט אחד
הגדרה של תמונה מונפשת. כדי לשלוט באנימציה, צריך להשתמש בנתונים בקטעי הקוד 'ANIM' ו-'ANMF'.
שמור (R): ביט אחד
חייב להיות 0. הקוראים חייבים להתעלם מהשדה הזה.
שמור: 24 סיביות
חייב להיות 0. הקוראים חייבים להתעלם מהשדה הזה.
רוחב קנבס מינוס אחד: 24 ביטים
רוחב הלוח בפיקסלים,
מתחיל ב-1. רוחב ההדפסה על קנבס בפועל הוא 1 + Canvas Width Minus One.
גובה ההדפסה על קנבס מינוס אחד: 24 ביט
הגובה של לוח הציור בפיקסלים,
מתחיל ב-1. גובה הקנבס בפועל הוא 1 + Canvas Height Minus One.

המוצר של רוחב הקנבס וגובה הקנבס צריך להיות 2^32 - 1 לכל היותר.

יכול להיות שבמפרטים עתידיים יתווספו עוד שדות. חובה להתעלם משדות לא מוכרים.

Animation

אנימציה נשלטת על ידי קטעי קוד מסוג 'ANIM' ו-'ANMF'.

מקטע 'ANIM':

בתמונה עם אנימציה, הקטע הזה מכיל את הפרמטרים הגלובליים של האנימציה.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('ANIM')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Background Color                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Loop Count           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
צבע רקע: 32 סיביות (uint32)
צבע הרקע שמוגדר כברירת מחדל ללוח הציור בסדר הבייטים [כחול, ירוק, אדום, אלפא]. ייתכן שהצבע הזה ימלא את השטח שלא נוצל על גבי הקנבס שמסביב למסגרות, וכן את הפיקסלים השקופים של המסגרת הראשונה. צבע הרקע משמש גם כששיטת הטיפול בתמונות קודמות היא 1.

הערות:

  • צבע הרקע יכול להכיל ערך אלפא לא אטום, גם אם הדגל Alpha בקטע'VP8X' לא מוגדר.

  • אפליקציות צפייה צריכות להתייחס לערך של צבע הרקע כהצעה, ולא חייבות להשתמש בו.

  • הלוח נמחק בתחילת כל לולאה. אפשר להשתמש בצבע הרקע כדי להשיג את התוצאה הזו.

מספר לולאות: 16 סיביות (uint16)
מספר הפעמים שהאנימציה תפעל בלופ. אם הערך הוא 0, המשמעות היא ללא הגבלת זמן.

הקטע הזה חייב להופיע אם הסימון Animation מוגדר בקטע 'VP8X'. אם הדגל Animation לא מוגדר ויש את המקטע הזה, צריך להתעלם ממנו.

מקטע 'ANMF':

בתמונות אנימציה, הקטע הזה מכיל מידע על מסגרת אחת. אם הדגל אנימציה לא מוגדר, המקטע הזה לא אמור להופיע.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('ANMF')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Frame X                |             ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
...          Frame Y            |   Frame Width Minus One     ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
...             |           Frame Height Minus One              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                 Frame Duration                |  Reserved |B|D|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                         Frame Data                            :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
מסגרת X: 24 סיביות (uint24)
הקואורדינטה X של הפינה השמאלית העליונה של המסגרת היא Frame X * 2.
מסגרת Y: 24 ביטים (uint24)
קואורדינטת ה-Y של הפינה השמאלית העליונה של המסגרת היא Frame Y * 2.
רוחב המסגרת מינוס אחד: 24 ביט (uint24)
רוחב המסגרת שמתחיל ב-1. רוחב המסגרת הוא 1 + Frame Width Minus One.
גובה הפריים מינוס אחד: 24 ביט (uint24)
הגובה של המסגרת מתחיל ב-1. גובה המסגרת הוא 1 + Frame Height Minus One.
משך המסגרת: 24 ביטים (uint24)
משך הזמן להמתנה לפני הצגת המסגרת הבאה, ביחידות של אלפית שנייה. שימו לב שהפירוש של Frame Duration ש-0 (ולרוב <= 10) מוגדר על ידי ההטמעה. בכלים ובדפדפנים רבים מקצים משך זמן מינימלי שדומה ל-GIF.
שמורים: 6 ביטים
חייב להיות 0. הקוראים חייבים להתעלם מהשדה הזה.
שיטת המיזוג (B): 1 ביט

מציינת את מידת המיזוג של פיקסלים שקופים של המסגרת הנוכחית עם פיקסלים תואמים של אזור העריכה הקודם:

  • 0: שימוש בשילוב אלפא. אחרי שמסירים את המסגרת הקודמת, מבצעים עיבוד (רנדור) של המסגרת הנוכחית על גבי הלוח באמצעות מיזוג אלפא (ראו בהמשך). אם לפריים הנוכחי אין ערוץ אלפא, נניח שערך האלפא הוא 255, ובכך מחליפים את המלבן.

  • 1: אין למזג. אחרי שמסירים את המסגרת הקודמת, צריך לעבד את המסגרת הנוכחית באזור העריכה על ידי החלפת המלבן שמכוסה על ידי המסגרת הנוכחית.

שיטת השלכה (D): ביט אחד

מציין איך הפריים הנוכחי יטופל אחרי שהוא יוצג (לפני עיבוד הפריימים הבאים) על הלוח:

  • 0: אין להשליך. משאירים את הקנבס כמו שהוא.

  • 1: Dispose לצבע הרקע. ממלאים את המלבן בבד הציור שמכוסה על ידי הפריים הנוכחי בצבע הרקע שצוין בקטע'ANIM'.

הערות:

  • ביטול הפריים חל רק על ריבוע הפריים, כלומר על הריבוע שמוגדר על ידי Frame X,‏ Frame Y,‏ frame width ו-frame height. הן יכסו את כל השטח של קנבס, אבל לא בהכרח.

  • מיזוג אלפא:

    מכיוון שכל אחד מהערוצים R, G, B ו-A הוא 8 ביט, וערוצי ה-RGB לא מוכפלים מראש באלפא, הנוסחה למיזוג 'dst' עם 'src' היא:

    blend.A = src.A + dst.A * (1 - src.A / 255)
    if blend.A = 0 then
      blend.RGB = 0
    else
      blend.RGB =
          (src.RGB * src.A +
           dst.RGB * dst.A * (1 - src.A / 255)) / blend.A
    
  • צריך לבצע שילוב אלפא של הצבעים במרחב צבעים ליניארי, על ידי התייחסות לפרופיל הצבע של התמונה. אם פרופיל הצבע לא נמצא, המערכת תשתמש ב-RGB רגיל (sRGB). (שימו לב שגם sRGB צריך לעבור ליניאריזציה בגלל ערך גמא של כ-2.2).

נתוני מסגרת: Chunk Size בייטים – 16

מורכב מ:

הערה: נתוני המסגרת, מטען העבודה של ANMF, מורכבים מקטעים מאוחסים נפרדים, כפי שמתואר בפורמט הקובץ RIFF.

אלפא

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('ALPH')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv| P | F | C |     Alpha Bitstream...                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
שמורות (Rsv): 2 ביטים
חייב להיות 0. הקוראים חייבים להתעלם מהשדה הזה.
עיבוד מקדים (P): 2 ביטים

הביטים האינפורמטיביים האלה משמשים כדי לסמן את העיבוד מראש שבוצעו במהלך הדחיסה. המקודד יכול להשתמש במידע הזה, למשל, כדי לבצע דיטיר (dither) של הערכים או להחליק את העקומות לפני הצגה.

  • 0: ללא עיבוד מקדים.
  • 1: הפחתת רמה.

לא חובה להשתמש במידע הזה בקודקים בדרך מסוימת.

שיטת סינון (F): 2 ביטים

שיטות הסינון שבהן נעשה שימוש מתוארות באופן הבא:

  • 0: None.
  • 1: מסנן אופקי.
  • 2: מסנן 'תחום עניין'.
  • 3: מסנן גוון מדורג.

הסינון מתבצע לכל פיקסל באמצעות החישובים הבאים. נניח שערכי האלפא שמקיפים את המיקום הנוכחי של X מסומנים בתווית:

 C | B |
---+---+
 A | X |

אנחנו רוצים לחשב את ערך האלפא במיקום X. בשלב הראשון מתבצע חיזוי בהתאם לשיטת הסינון:

  • שיטה 0: predictor = 0
  • שיטה 1: predictor = A
  • שיטה 2: predictor = B
  • שיטה 3: predictor = clip(A + B - C)

כאשר clip(v) שווה ל-:

  • 0 אם v < 0,
  • 255 אם v > 255, או
  • v אחרת

הערך הסופי נגזר מהוספת הערך הלא דחוס X לחזאי, ושימוש באריתמטיקה של modulo-256 כדי לעטוף את הטווח [256..511] בטווח [0..255]:

alpha = (predictor + X) % 256

יש מקרים מיוחדים למיקומי הפיקסלים הימני והעליון. לדוגמה, הערך בפינה השמאלית העליונה במיקום (0, 0) משתמש ב-0 בתור ערך החיזוי. אחרת:

  • בשיטות של סינון אופקי או סינון שיפוע, הפיקסלים שמשמאל ביותר במיקום (0, y) חזויים באמצעות המיקום (0, y-1) שמעליו.
  • בשיטות סינון אנכיות או הדרגתיות, הפיקסלים העליונים במיקום (x, 0) צפויים לפי המיקום (x-1, 0) בצד שמאל.
שיטת דחיסה (C): 2 ביט

שיטת הדחיסה שבה נעשה שימוש:

  • 0: ללא דחיסת נתונים.
  • 1: דחוס באמצעות הפורמט ללא אובדן נתונים של WebP.
מקור נתונים אלפא: Chunk Size בייטים – 1

מקודד של זרם ביטים של אלפא.

הקטע האופציונלי הזה מכיל נתוני אלפא מקודדים של המסגרת הזו. פריים שמכיל מקטע 'VP8L' לא אמור להכיל את המקטע הזה.

הסיבה: פרטי השקיפות כבר כלולים ב-Chunk‏ 'VP8L'.

נתוני הערוץ אלפא מאוחסנים כנתונים גולמיים לא דחוסים (כששיטת הדחיסה היא '0') או דחוסים בפורמט ללא איבוד נתונים (כששיטת הדחיסה היא '1').

  • נתונים גולמיים: מורכב מרצף של בייטים באורך = רוחב * גובה, שמכיל את כל ערכי השקיפות של 8 ביט לפי סדר הסריקה.

  • דחיסת פורמט ללא אובדן נתונים: רצף הבייטים הוא מקור תמונות דחוס (כפי שמתואר בקטע פורמט מקור ביט ללא אובדן נתונים של WebP) של מידות מרומזות: רוחב x גובה. כלומר, ה-image-stream הזה לא מכיל כותרות שמתארות את מידות התמונה.

    הסיבה: המאפיינים כבר ידועים ממקורות אחרים, ולכן אחסון שלהם שוב יהיה מיותר וסביר להניח שיגרום לשגיאות.

    אחרי שהקוד של מקור התמונה מפוענח לערכים של צבעים (אלפא, אדום, ירוק, כחול, ARGB), בהתאם לתהליך שמתואר במפרט של הפורמט ללא אובדן נתונים, צריך לחלץ את פרטי השקיפות מהערוץ הירוק של ה-quadruplet‏ ARGB.

    הסיבה: לערוץ הירוק מותר לבצע שלבי טרנספורמציה נוספים במפרט – בניגוד לשאר הערוצים – שיכולים לשפר את דחיסת הנתונים.

נתיב נתונים (VP8/VP8L)

הרצף הזה מכיל נתוני זרם ביטים דחוסים של פריים יחיד.

מקטע של מקור נתונים יכול להיות (1) מקטע מסוג 'VP8 ', עם 'VP8 ' (שימו לב למרווח המשמעותי בתו הרביעי) כ-FourCC, או (2) מקטע מסוג 'VP8L', עם 'VP8L' כ-FourCC.

הפורמטים של המקטעים 'VP8' ו-'VP8L' מתוארים בסעיפים Simple File Format (Lossy) ו-Simple File Format (Lossless) בהתאמה.

פרופיל צבע

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('ICCP')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                       Color Profile                           :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
פרופיל צבע: Chunk Size בייטים
פרופיל ICC.

הקטע הזה חייב להופיע לפני נתוני התמונה.

צריך להיות מקסימום מקטע אחד כזה. אם יש עוד קטעים כאלה, הקוראים יכולים להתעלם מכל הקטעים חוץ מהקטע הראשון. פרטים נוספים זמינים במפרט ICC.

אם הקטע הזה לא קיים, צריך להניח שמדובר ב-sRGB.

מטא-נתונים

אפשר לאחסן מטא-נתונים בקטעי 'EXIF' או 'XMP '.

צריך להיות מקטע אחד לכל היותר מכל סוג ('EXIF' ו-'XMP'). אם יש יותר מקטעים כאלה, יכול להיות שהקוראים יתעלמו מכל המקטעים מלבד הראשון.

הקטעים מוגדרים כך:

מקטע 'EXIF':

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('EXIF')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                        Exif Metadata                          :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
מטא-נתונים של Exif: Chunk Size בייטים
מטא-נתונים של תמונה בפורמט Exif.

מקטע 'XMP ':

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('XMP ')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                        XMP Metadata                           :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
מטא-נתונים של XMP: בייטים בגודל מקטע
מטא-נתונים של תמונה בפורמט XMP.

הערה: התו הרביעי ב-FourCC של 'XMP ' הוא רווח ASCII (0x20).

הנחיות נוספות לגבי טיפול במטא-נתונים מופיעות במאמר "הנחיות לטיפול במטא-נתונים" של קבוצת העבודה במטא-נתונים.

קטעי קוד לא ידועים

מקטע RIFF (כפי שמתואר בקטע RIFF File Format) שה-FourCC שלו שונה מכל המקטעים שמתוארים במסמך הזה, נחשב למקטע לא ידוע.

הסיבה: האפשרות לאפשר קטעי נתונים לא מוכרים מאפשרת להרחיב את הפורמט בעתיד, וגם לאחסן נתונים ספציפיים לאפליקציה.

יכול להיות שהקובץ מכיל מקטעים לא ידועים:

הקוראים צריכים להתעלם ממקטעי הנתונים האלה. הכותבים צריכים לשמור אותם בסדר המקורי שלהם (אלא אם הם מתכוונים לשנות את הקטעים האלה באופן ספציפי).

הרכבה של הדפסה על קנבס ממסגרות

כאן נספק סקירה כללית של האופן שבו קורא חייב להרכיב קנבס במקרה של תמונה מונפשת.

התהליך מתחיל ביצירת לוח קנבס לפי המימדים שצוינו ב-chunk של VP8X, Canvas Width Minus One + 1 פיקסלים ברוחב ו-Canvas Height Minus One + 1 פיקסלים בגובה. השדה Loop Count מהקטע 'ANIM' קובע כמה פעמים תהליך האנימציה יחזור על עצמו. הערך הזה הוא Loop Count - 1 לערכים של Loop Count שאינם אפס, או אינסוף אם הערך של Loop Count הוא אפס.

בתחילת כל חזרה של לולאה, אזור העריכה ממולא בצבע הרקע של קבוצת ANIM או בצבע שהוגדר על ידי האפליקציה.

קטעי 'ANMF' מכילים פריימים נפרדים שמופיעים בסדר הצגה. לפני עיבוד הגרפי של כל מסגרת, המערכת מחילה את Disposal method של המסגרת הקודמת.

העיבוד של המסגרת המקודדת מתחיל בקואורדינטות הקרטזיות (2 * Frame X, 2 * Frame Y), תוך שימוש בפינה הימנית העליונה של הלוח כמקור. ברוחב של Frame Width Minus One + 1 פיקסלים ובגובה של Frame Height Minus One + 1 פיקסלים מעובדים אל אזור העריכה באמצעות Blending method.

הקנבס מוצג למשך Frame Duration אלפיות השנייה. המצב הזה נמשך עד שכל הפריימים שניתנו על ידי מקטעי 'ANMF' יוצגו. לאחר מכן מתחילה חזרה חדשה של הלולאה, או שהלוח נשאר במצב הסופי שלו אם כל החזרות הסתיימו.

הקוד המדומה הבא מדגים את תהליך הרינדור. הסימון VP8X.field מציין את השדה ב-Chunk‏ 'VP8X' עם אותו תיאור.

VP8X.flags.hasAnimation MUST be TRUE
canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with
         background color ANIM.background_color or
         application-defined color.
loop_count ← ANIM.loopCount
dispose_method ← Dispose to background color
if loop_count == 0:
  loop_count = ∞
frame_params ← nil
next chunk in image_data is ANMF MUST be TRUE
for loop = 0..loop_count - 1
  clear canvas to ANIM.background_color or application-defined color
  until eof or non-ANMF chunk
    frame_params.frameX = Frame X
    frame_params.frameY = Frame Y
    frame_params.frameWidth = Frame Width Minus One + 1
    frame_params.frameHeight = Frame Height Minus One + 1
    frame_params.frameDuration = Frame Duration
    frame_right = frame_params.frameX + frame_params.frameWidth
    frame_bottom = frame_params.frameY + frame_params.frameHeight
    VP8X.canvasWidth >= frame_right MUST be TRUE
    VP8X.canvasHeight >= frame_bottom MUST be TRUE
    for subchunk in 'Frame Data':
      if subchunk.tag == "ALPH":
        alpha subchunks not found in 'Frame Data' earlier MUST be
          TRUE
        frame_params.alpha = alpha_data
      else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
        bitstream subchunks not found in 'Frame Data' earlier MUST
          be TRUE
        frame_params.bitstream = bitstream_data
    apply dispose_method.
    render frame with frame_params.alpha and frame_params.bitstream
      on canvas with top-left corner at (frame_params.frameX,
      frame_params.frameY), using Blending method
      frame_params.blendingMethod.
    canvas contains the decoded image.
    Show the contents of the canvas for
    frame_params.frameDuration * 1 ms.
    dispose_method = frame_params.disposeMethod

פריסות קבצים לדוגמה

תמונה עם אלפא בקידוד עם אובדן נתונים עשויה להיראות כך:

RIFF/WEBP
+- VP8X (descriptions of features used)
+- ALPH (alpha bitstream)
+- VP8 (bitstream)

תמונה בקידוד ללא אובדן נתונים עשויה להיראות כך:

RIFF/WEBP
+- VP8X (descriptions of features used)
+- VP8L (lossless bitstream)
+- XYZW (unknown chunk)

תמונה ללא אובדן נתונים עם פרופיל ICC ומטא-נתונים של XMP עשויה להיראות כך:

RIFF/WEBP
+- VP8X (descriptions of features used)
+- ICCP (color profile)
+- VP8L (lossless bitstream)
+- XMP  (metadata)

תמונה מונפשת עם מטא-נתונים של תצוגת Exif עשויה להיראות כך:

RIFF/WEBP
+- VP8X (descriptions of features used)
+- ANIM (global animation parameters)
+- ANMF (frame1 parameters + data)
+- ANMF (frame2 parameters + data)
+- ANMF (frame3 parameters + data)
+- ANMF (frame4 parameters + data)
+- EXIF (metadata)