מפרט מאגר WebP

מבוא

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

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

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

  • מטא-נתונים: לתמונה יכולים להיות מטא-נתונים שמאוחסנים בפורמט Exchangeable Image File (Exif) או בפורמט Extensible Metadata Platform (XMP).

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

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

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

מתן שם

מומלץ להשתמש בסוגים הבאים בתור הפנייה לקונטיינר של WebP:

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

טרמינולוגיה ויסודות

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

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

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

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

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

פורמט קובץ RIFF

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

הרכיב הבסיסי של קובץ 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                         :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Chink ForCC: 32 סיביות
קוד ASCII בן ארבעה תווים המשמש לזיהוי המקטעים.
גודל קבוצת הנתונים: 32 סיביות (uint32)
גודל המקטע בבייטים, לא כולל השדה הזה, מזהה המקטע או המרווח הפנימי.
מטען ייעודי (payload): Chunk size בייטים
מטען הייעודי (payload) של הנתונים. במקרה שהערך של ChunkSize הוא אי-זוגי, מתווסף בייט יחיד של מרווח פנימי (שחייב להיות 0 כדי להתאים ל-RIFF).

הערה: ל-RIFF יש מוסכמה ש-FourCCs של מקטעים באותיות גדולות בלבד הם מקטעים סטנדרטיים שחלים על כל פורמט של קובץ RIFF, בעוד ש-FourCCs שספציפיים לפורמט קובץ הוא אותיות קטנות. 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 בייטים, ולכן הגודל של הקובץ כולו הוא 4GiB פחות 2 בייטים.
'WEBP': 32 סיביות
תווי ASCII 'W', 'E', 'B', 'P'.

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

פורמט קובץ פשוט (אובדן)

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

פורמט קובץ פשוט WebP (lossy):

 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 ' chunk:

 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 ב-bitstream.

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

המפרט של פורמט הנתונים VP8 מתואר במדריך לפורמט נתונים ולפענוח 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 בייטים
נתוני VP8L ב-bitstream.

המפרט הנוכחי של ה-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): ביט אחד
קביעה אם מדובר בתמונה מונפשת. כדי לשלוט באנימציה, יש להשתמש בנתונים מקטעי ה-ANMF ו-ANMF.
שמור (R): ביט אחד
חייב להיות 0. הקוראים לא יכולים להתעלם מהשדה הזה.
שמור: 24 סיביות
חייב להיות 0. הקוראים לא יכולים להתעלם מהשדה הזה.
רוחב לוח הציור מינוס 1: 24 סיביות
רוחב אחד מבוסס של הקנבס בפיקסלים. רוחב הקנבס בפועל הוא 1 + Canvas Width Minus One.
גובה הקנבס – מינוס 1: 24 ביטים
גובה אחד מבוסס של הקנבס בפיקסלים. גובה הקנבס בפועל הוא 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.

הערה:

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

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

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

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

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

גוש '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.
רוחב המסגרת מינוס 1: 24 ביטים (uint24)
רוחב המבוסס אחד של המסגרת. רוחב המסגרת הוא 1 + Frame Width Minus One.
גובה המסגרת מינוס 1: 24 ביטים (uint24)
גובה המבוסס על 1 של המסגרת. גובה המסגרת הוא 1 + Frame Height Minus One.
משך מסגרת: 24 סיביות (uint24)
הזמן שצריך להמתין לפני הצגת הפריים הבא, ביחידות של אלפית שנייה. שימו לב שההטמעה של משך המסגרת של 0 (ולעיתים קרובות גם <= 10) מוגדרת על ידי ההטמעה. כלים ודפדפנים רבים מקצים משך זמן מינימלי בדומה ל-GIF.
שמור: 6 סיביות
חייב להיות 0. הקוראים לא יכולים להתעלם מהשדה הזה.
שיטת שילוב (B): ביט אחד

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

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

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

שיטת סילוק (D): ביט אחד

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

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

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

הערות:

  • הסרת המסגרת חלה רק על מלבן המסגרת, כלומר, המלבן המוגדר על ידי Frame X, Frame Y, framewidth ו-frameheight. הוא יכול לכסות את כל שטח הקנבס, אבל לא בהכרח.

  • מיזוג אלפא:

    בהתחשב בעובדה שכל אחד מהערוצים 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 בערך).

נתוני פריימים: גודל צ'אנק16 בייטים

מורכב מ:

הערה: המטען הייעודי (payload) של 'ANMF', Frame Data, מורכב ממקטעים מרופדים נפרדים, כפי שמתואר בפורמט הקובץ 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 ביטים

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

  • 0: אין עיבוד מראש.
  • 1: ירידה ברמה.

מפענחים לא נדרשים להשתמש במידע הזה בשום צורה.

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

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

  • 0: אין.
  • 1: מסנן אופקי.
  • 2: מסנן אנכי.
  • 3: מסנן הדרגתי.

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

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

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

  • שיטה 0: חיזוי = 0
  • שיטה 1: חיזוי = A
  • שיטה 2: חיזוי = B
  • שיטה 3: חיזוי = קליפ(A + B - C)

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

  • 0 אם v < 0,
  • 255 אם v > 255, או
  • V אם לא

הערך הסופי נגזר מהוספת הערך הדחוס X לחיזוי, ושימוש בחשבון מודולו-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 Lossless.
Alpha Bistream: גודל צ'אנק1 בייטים

קידוד אלפא ביטstream.

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

הנימוק: מידע השקיפות כבר כלול ברשימת 'VP8L'.

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

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

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

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

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

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

Bitstream (VP8/VP8L)

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

מקטע נתונים (bitstream) יכול להיות (i) מקטע 'VP8 ', משתמש ב-'VP8 ' (שימו לב לרווח המשמעותי התו הרביעי) בתור ה-FourCC שלו, או (ii) מקטע '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                           :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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: Chunk size בייטים
מטא-נתונים של תמונות בפורמט XMP.

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

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

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

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

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

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

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

הרכבת קנבס ממסגרות

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

התהליך מתחיל ביצירת לוח הציור באמצעות המידות שמוצגות בקבוצת ה-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 פירושו השדה בקבוצת VP8X עם תיאור זהה.

VP8X.flags.hasAnimation MUST be TRUE
canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with
         background color ANIM.background_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
    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)