מפרט מאגר WebP

מבוא

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

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

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

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

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

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

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

מתן שמות

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

שם פורמט של מאגרWebP
סיומת שם הקובץ.webp
סוג MIMEimage/webp
מזהה סוג אחיד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 ביט, בסדר קטן-גדול.
FourCC
קוד בן ארבעה תווים (FourCC) הוא uint32 שנוצר על ידי שרשור של ארבע תווי ASCII בסדר קטן מאוד. כלומר, 'aaaa'‏ (0x61616161) ו-'AAAA'‏ (0x41414141) נחשבים כFourCCs שונים.
בסיס 1
שדה של מספר שלם ללא סימן שמאחסן ערכים עם סטייה של -1. לדוגמה, בשדה כזה הערך 25 יישמר כ-24.
ChunkHeader('ABCD')
משמש לתיאור הכותרות FourCC ו-Chunk Size של קטעי קוד בודדים, כאשר 'ABCD' הוא ה-FourCC של קטע הקוד. הגודל של הרכיב הזה הוא 8 בייטים.

פורמט קובץ RIFF

פורמט הקובץ WebP מבוסס על RIFF (פורמט הקובץ של החלפת משאבים) פורמט המסמך.

הרכיב הבסיסי של קובץ 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 בייטים
מטען הנתונים. אם גודל הקבוצה הוא אי-זוגי, תו מרווח פנימי יחיד הוא בייט יחיד. להיות 0 כדי להתאים ל-RIFF – יתווסף.

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

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

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

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

פורמט קובץ 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: בייטים בגודל מקטע
נתוני VP8 bitstream.

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

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

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

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

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

יש להשתמש בפריסה הזו אם לתמונה נדרש קידוד 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: בייטים של גודל מקטע
נתוני מקור ביט של
VP8L.

ניתן למצוא את המפרט הנוכחי של ה-bitstream של VP8L פורמט WebP Lossless Bitstream. שימו לב שהכותרת 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)
משך הזמן להמתנה לפני הצגת המסגרת הבאה, ביחידות של אלפית שנייה. שימו לב שהפרשנות של משך המסגרת של 0 (ולרוב <= 10) היא מוגדר על ידי ההטמעה. כלים ודפדפנים רבים מקצים ערך מינימלי בדומה ל-GIF.
שמורים: 6 ביטים
חייב להיות 0. הקוראים חייבים להתעלם מהשדה הזה.
שיטת השילוב (B): ביט אחד

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

  • 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: ללא.
  • 1: מסנן אופקי.
  • 2: מסנן 'תחום עניין'.
  • 3: מסנן הדרגתי.

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

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

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

  • שיטה 0: חיזוי = 0
  • שיטה 1: חיזוי = A
  • שיטה 2: predictor = B
  • שיטה 3: חיזוי = קליפ(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 Lossless.
מקור נתונים ב-Alpha: Chunk Size בייטים – 1

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

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

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

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

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

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

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

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

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

Bitstream‏ (VP8/VP8L)

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

מקטע Bitstream יכול להיות (i) 'VP8' קבוצת משתמשים, באמצעות 'VP8' (שימו לב ל רווח משמעותי בתווים רביעיים) כ-FourCC, או (ii) 'VP8L' Chenk, באמצעות 'VP8L' כ-FourCC.

הפורמטים של 'VP8' ו-VP8L מקטעי נתונים כפי שמתואר במקטעים פורמט קובץ פשוט (לוסי) ו-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: גודל מקטע בייטים
מטא-נתונים של תמונה בפורמט 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.

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

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

גושים לא ידועים

מקטע RIFF (מתואר בקטע פורמט קובץ RIFF) שה-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 היא השדה בתוך '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)