תיעוד של WebP API

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

כותרות וספריות

כשמתקינים את libwebp, ספרייה בשם webp/ יותקן במיקום הרגיל של הפלטפורמה. לדוגמה, ב- בפלטפורמות Unix, קובצי הכותרות הבאים יועתקו אל /usr/local/include/webp/

decode.h
encode.h
types.h

הספריות ממוקמות בספריות הרגילות. את הערכים הסטטיים ספריות דינמיות נמצאות ב-/usr/local/lib/ בפלטפורמות Unix.

API פשוט של פענוח קוד

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

מוסיפים את כותרת ה-API לפענוח בקוד C/C++ באופן הבא:

#include "webp/decode.h"
int WebPGetInfo(const uint8_t* data, size_t data_size, int* width, int* height);

הפונקציה הזו תאמת את כותרת התמונה WebP ותאחזר את רוחב התמונה וגובה. אפשר להעביר את המצביעים *width ו-*height באמצעות NULL אם נקבע זאת לא רלוונטיות.

מאפייני קלט

נתונים
הפניה לנתוני תמונה של WebP
גודל_נתונים
זה הגודל של בלוק הזיכרון שאליו מפנה data שמכיל את של נתוני תמונה.

החזרות

false
הוחזר קוד שגיאה במקרה של (א) שגיאות פורמט.
true
להצלחה. המוצרים *width ו-*height תקפים רק להחזרה שהתבצעה בהצלחה.
רוחב
ערך של מספר שלם. הטווח מוגבל מ-1 ל-16383.
גובה
ערך של מספר שלם. הטווח מוגבל ל-1 עד 16383.
struct WebPBitstreamFeatures {
  int width;          // Width in pixels.
  int height;         // Height in pixels.
  int has_alpha;      // True if the bitstream contains an alpha channel.
  int has_animation;  // True if the bitstream is an animation.
  int format;         // 0 = undefined (/mixed), 1 = lossy, 2 = lossless
}

VP8StatusCode WebPGetFeatures(const uint8_t* data,
                              size_t data_size,
                              WebPBitstreamFeatures* features);

הפונקציה הזו תאחזר תכונות מה-bitstream. *features מלא במידע שנאסף מה-bitstream:

מאפייני קלט

נתונים
הפניה לנתוני תמונה של WebP
גודל_נתונים
זה הגודל של בלוק הזיכרון שאליו מפנה data שמכיל את של נתוני תמונה.

החזרות

VP8_STATUS_OK
כשהתכונות מאוחזרות בהצלחה.
VP8_STATUS_NOT_ENOUGH_DATA
כשיש צורך בנתונים נוספים כדי לאחזר את התכונות מכותרות.

במקרים אחרים, ערכי שגיאה נוספים מסוג VP8StatusCode.

תכונות
מצביע למבנה של WebPBitstreamFeatures.
uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size, int* width, int* height);
uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size, int* width, int* height);
uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size, int* width, int* height);
uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size, int* width, int* height);
uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size, int* width, int* height);

הפונקציות האלה מפענחות תמונת WebP שאליה מפנה data.

  • WebPDecodeRGBA מחזיר דוגמאות של תמונות RGBA בסדר [r0, g0, b0, a0, r1, g1, b1, a1, ...].
  • WebPDecodeARGB מחזיר דוגמאות של תמונות ARGB בסדר [a0, r0, g0, b0, a1, r1, g1, b1, ...].
  • WebPDecodeBGRA מחזירה דוגמאות של תמונות BGRA בסדר [b0, g0, r0, a0, b1, g1, r1, a1, ...].
  • WebPDecodeRGB מחזיר דוגמאות של תמונות RGB בסדר [r0, g0, b0, r1, g1, b1, ...].
  • WebPDecodeBGR מחזירה דוגמאות של תמונות BGR בהזמנה [b0, g0, r0, b1, g1, r1, ...].

הקוד שקורא לכל אחת מהפונקציות האלה צריך למחוק את מאגר הנתונים הזמני הפונקציה (uint8_t*) מחזירה על ידי הפונקציות האלה עם WebPFree().

מאפייני קלט

נתונים
הפניה לנתוני תמונה של WebP
גודל_נתונים
זה הגודל של בלוק הזיכרון שאליו מפנה data שמכיל את נתוני תמונה
רוחב
ערך של מספר שלם. הטווח מוגבל כרגע מ-1 ל-16383.
גובה
ערך של מספר שלם. הטווח מוגבל כרגע מ-1 ל-16383.

החזרות

uint8_t*
מצביע לדוגמאות של תמונות WebP מפוענחות בפורמט RGBA/ARGB/BGRA/RGB/BGR ליניארי בסדר, בהתאמה.
uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size,
                            uint8_t* output_buffer, int output_buffer_size, int output_stride);
uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size,
                            uint8_t* output_buffer, int output_buffer_size, int output_stride);
uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size,
                            uint8_t* output_buffer, int output_buffer_size, int output_stride);
uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size,
                           uint8_t* output_buffer, int output_buffer_size, int output_stride);
uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size,
                           uint8_t* output_buffer, int output_buffer_size, int output_stride);

הפונקציות האלה הן וריאציות של הפונקציות שלמעלה ומפענחות את התמונה ישירות למאגר הנתונים הזמני output_buffer שהוקצה מראש. נפח האחסון המקסימלי שזמין ב- מאגר הנתונים הזמני הזה מסומן על ידי output_buffer_size. אם נפח האחסון הזה לא פנוי מספיק (או שאירעה שגיאה), מוחזר NULL. אחרת, מטעמי נוחות, מוחזר output_buffer.

הפרמטר output_stride מציין את המרחק (בבייטים) בין קווי סריקה. לכן, output_buffer_size צפוי להיות לפחות output_stride * picture - height.

מאפייני קלט

נתונים
הפניה לנתוני תמונה של WebP
גודל_נתונים
זה הגודל של בלוק הזיכרון שאליו מפנה data שמכיל את נתוני תמונה
output_buffer_size
ערך של מספר שלם. גודל המאגר שהוקצה
output_stride
ערך של מספר שלם. מציינת את המרחק בין קווי סריקה.

החזרות

output_buffer
מצביע לתמונה WebP מפוענחת.
uint8_t*
output_buffer אם הפונקציה מצליחה; NULL אם לא.

API מתקדם של פענוח קוד

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

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

קודם כל צריך לאתחל אובייקט תצורה:

#include "webp/decode.h"

WebPDecoderConfig config;
CHECK(WebPInitDecoderConfig(&config));

// One can adjust some additional decoding options:
config.options.no_fancy_upsampling = 1;
config.options.use_scaling = 1;
config.options.scaled_width = scaledWidth();
config.options.scaled_height = scaledHeight();
// etc.

אפשרויות הפענוח נאספות בתוך WebPDecoderConfig מבנה:

struct WebPDecoderOptions {
  int bypass_filtering;             // if true, skip the in-loop filtering
  int no_fancy_upsampling;          // if true, use faster pointwise upsampler
  int use_cropping;                 // if true, cropping is applied first 
  int crop_left, crop_top;          // top-left position for cropping.
                                    // Will be snapped to even values.
  int crop_width, crop_height;      // dimension of the cropping area
  int use_scaling;                  // if true, scaling is applied afterward
  int scaled_width, scaled_height;  // final resolution
  int use_threads;                  // if true, use multi-threaded decoding
  int dithering_strength;           // dithering strength (0=Off, 100=full)
  int flip;                         // if true, flip output vertically
  int alpha_dithering_strength;     // alpha dithering strength in [0..100]
};

אפשר גם לקרוא את תכונות ה-bitstream ב-config.input, למקרה שנצטרך לדעת אותם מראש. לדוגמה, יכול להיות שנדע האם יש בתמונה שקיפות מסוימת. לתשומת ליבכם: לנתח גם את הכותרת של ה-bitstream, ולכן זו דרך טובה לדעת אם ה-bitstream נראה כמו WebP תקין.

CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK);

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

// Specify the desired output colorspace:
config.output.colorspace = MODE_BGRA;
// Have config.output point to an external buffer:
config.output.u.RGBA.rgba = (uint8_t*)memory_buffer;
config.output.u.RGBA.stride = scanline_stride;
config.output.u.RGBA.size = total_size_of_the_memory_buffer;
config.output.is_external_memory = 1;

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

CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK);

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

WebPIDecoder* idec = WebPINewDecoder(&config.output);
CHECK(idec != NULL);
while (additional_data_is_available) {
  // ... (get additional data in some new_data[] buffer)
  VP8StatusCode status = WebPIAppend(idec, new_data, new_data_size);
  if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
    break;
  }
  // The above call decodes the current available buffer.
  // Part of the image can now be refreshed by calling
  // WebPIDecGetRGB()/WebPIDecGetYUVA() etc.
}
WebPIDelete(idec);  // the object doesn't own the image memory, so it can
                    // now be deleted. config.output memory is preserved.

התמונה שמקודדת היא עכשיו ב-config.output (או במקום זאת ב-config.output.u.RGBA במקרה הזה, מכיוון שמרחב הצבעים של הפלט המבוקש היה מצב_BGRA). תמונת יכול להישמר, להציג או לעבד אותם בדרך אחרת. לאחר מכן, אנחנו צריכים רק לשחזר מחדש את הזיכרון שהוקצה באובייקט config. ניתן לקרוא לפונקציה הזו ללא חשש, גם אם הזיכרון הוא חיצוני הוקצה על ידי WebPDecode():

WebPFreeDecBuffer(&config.output);

באמצעות ה-API הזה אפשר גם לפענח את התמונה לפורמטים YUV ו-YUVA, באמצעות MODE_YUV ו-MODE_YUVA בהתאמה. הפורמט הזה נקרא גם Y'CbCr.

ממשק API של קידוד פשוט

יש כמה פונקציות פשוטות מאוד לקידוד מערכי נתונים של דגימות RGBA בפריסות הנפוצות ביותר. הן מוצהרות בwebp/encode.h כותרת בתור:

size_t WebPEncodeRGB(const uint8_t* rgb, int width, int height, int stride, float quality_factor, uint8_t** output);
size_t WebPEncodeBGR(const uint8_t* bgr, int width, int height, int stride, float quality_factor, uint8_t** output);
size_t WebPEncodeRGBA(const uint8_t* rgba, int width, int height, int stride, float quality_factor, uint8_t** output);
size_t WebPEncodeBGRA(const uint8_t* bgra, int width, int height, int stride, float quality_factor, uint8_t** output);

גורם האיכות quality_factor נע בין 0 ל-100 שולטת באובדן ובאיכות במהלך הדחיסה. הערך 0 תואם לערך נמוך פלט איכותי או קטן, ואילו 100 הוא האיכות הגבוהה ביותר גודל הפלט. לאחר הפעולה בהצלחה, הבייטים הדחוסים מוצבים בפונקציה *output של הסמן, והגודל בבייטים מוחזר (אחרת מוחזר 0, במקרה כשל). המתקשר צריך להתקשר למספר WebPFree() ב*output כדי לשחזר את הזיכרון.

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

יש פונקציות מקבילות לקידוד ללא אובדן מידע, שכוללות חתימות:

size_t WebPEncodeLosslessRGB(const uint8_t* rgb, int width, int height, int stride, uint8_t** output);
size_t WebPEncodeLosslessBGR(const uint8_t* bgr, int width, int height, int stride, uint8_t** output);
size_t WebPEncodeLosslessRGBA(const uint8_t* rgba, int width, int height, int stride, uint8_t** output);
size_t WebPEncodeLosslessBGRA(const uint8_t* bgra, int width, int height, int stride, uint8_t** output);

שימו לב שהפונקציות האלה, כמו הגרסאות עם איבוד נתונים, משתמשות בברירת המחדל של הספרייה הגדרות. עבור Lossless, המשמעות היא 'מדויקת' מושבתת. ערכי RGB ב: אזורים שקופים ישתנו כדי לשפר את הדחיסה. כדי להימנע מכך, השתמשו WebPEncode() ומגדירים את WebPConfig::exact לערך 1.

ממשק API לקידוד מתקדם

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

struct WebPConfig {
  int lossless;           // Lossless encoding (0=lossy(default), 1=lossless).
  float quality;          // between 0 and 100. For lossy, 0 gives the smallest
                          // size and 100 the largest. For lossless, this
                          // parameter is the amount of effort put into the
                          // compression: 0 is the fastest but gives larger
                          // files compared to the slowest, but best, 100.
  int method;             // quality/speed trade-off (0=fast, 6=slower-better)

  WebPImageHint image_hint;  // Hint for image type (lossless only for now).

  // Parameters related to lossy compression only:
  int target_size;        // if non-zero, set the desired target size in bytes.
                          // Takes precedence over the 'compression' parameter.
  float target_PSNR;      // if non-zero, specifies the minimal distortion to
                          // try to achieve. Takes precedence over target_size.
  int segments;           // maximum number of segments to use, in [1..4]
  int sns_strength;       // Spatial Noise Shaping. 0=off, 100=maximum.
  int filter_strength;    // range: [0 = off .. 100 = strongest]
  int filter_sharpness;   // range: [0 = off .. 7 = least sharp]
  int filter_type;        // filtering type: 0 = simple, 1 = strong (only used
                          // if filter_strength > 0 or autofilter > 0)
  int autofilter;         // Auto adjust filter's strength [0 = off, 1 = on]
  int alpha_compression;  // Algorithm for encoding the alpha plane (0 = none,
                          // 1 = compressed with WebP lossless). Default is 1.
  int alpha_filtering;    // Predictive filtering method for alpha plane.
                          //  0: none, 1: fast, 2: best. Default if 1.
  int alpha_quality;      // Between 0 (smallest size) and 100 (lossless).
                          // Default is 100.
  int pass;               // number of entropy-analysis passes (in [1..10]).

  int show_compressed;    // if true, export the compressed picture back.
                          // In-loop filtering is not applied.
  int preprocessing;      // preprocessing filter (0=none, 1=segment-smooth)
  int partitions;         // log2(number of token partitions) in [0..3]
                          // Default is set to 0 for easier progressive decoding.
  int partition_limit;    // quality degradation allowed to fit the 512k limit on
                          // prediction modes coding (0: no degradation,
                          // 100: maximum possible degradation).
  int use_sharp_yuv;      // if needed, use sharp (and slow) RGB->YUV conversion
};

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

צריך להקיף את דוגמאות הקלט במבנה WebPPicture. במבנה הזה אפשר לאחסן דוגמאות קלט בפורמט RGBA או YUVA, בהתאם בערך של הדגל use_argb.

המבנה מאורגן כך:

struct WebPPicture {
  int use_argb;              // To select between ARGB and YUVA input.

  // YUV input, recommended for lossy compression.
  // Used if use_argb = 0.
  WebPEncCSP colorspace;     // colorspace: should be YUVA420 or YUV420 for now (=Y'CbCr).
  int width, height;         // dimensions (less or equal to WEBP_MAX_DIMENSION)
  uint8_t *y, *u, *v;        // pointers to luma/chroma planes.
  int y_stride, uv_stride;   // luma/chroma strides.
  uint8_t* a;                // pointer to the alpha plane
  int a_stride;              // stride of the alpha plane

  // Alternate ARGB input, recommended for lossless compression.
  // Used if use_argb = 1.
  uint32_t* argb;            // Pointer to argb (32 bit) plane.
  int argb_stride;           // This is stride in pixels units, not bytes.

  // Byte-emission hook, to store compressed bytes as they are ready.
  WebPWriterFunction writer;  // can be NULL
  void* custom_ptr;           // can be used by the writer.

  // Error code for the latest error encountered during encoding
  WebPEncodingError error_code;
};

למבנה הזה יש גם פונקציה שמפיקה את הבייטים הדחוסים, זמינים. למטה יש דוגמה עם 'כתיבה בזיכרון'. בעלי הרשאת כתיבה אחרים יכולים לאחסן נתונים ישירות בקובץ (מידע נוסף examples/cwebp.c לדוגמה כזו).

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

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

#include "webp/encode.h"

WebPConfig config;
if (!WebPConfigPreset(&config, WEBP_PRESET_PHOTO, quality_factor)) return 0;   // version error

// Add additional tuning:
config.sns_strength = 90;
config.filter_sharpness = 6;
config.alpha_quality = 90;
config_error = WebPValidateConfig(&config);  // will verify parameter ranges (always a good habit)

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

// Setup the input data, allocating a picture of width x height dimension
WebPPicture pic;
if (!WebPPictureInit(&pic)) return 0;  // version error
pic.width = width;
pic.height = height;
if (!WebPPictureAlloc(&pic)) return 0;   // memory error

// At this point, 'pic' has been initialized as a container, and can receive the YUVA or RGBA samples.
// Alternatively, one could use ready-made import functions like WebPPictureImportRGBA(), which will take
// care of memory allocation. In any case, past this point, one will have to call WebPPictureFree(&pic)
// to reclaim allocated memory.

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

// Set up a byte-writing method (write-to-memory, in this case):
WebPMemoryWriter writer;
WebPMemoryWriterInit(&writer);
pic.writer = WebPMemoryWrite;
pic.custom_ptr = &writer;

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

int ok = WebPEncode(&config, &pic);
WebPPictureFree(&pic);   // Always free the memory associated with the input.
if (!ok) {
  printf("Encoding error: %d\n", pic.error_code);
} else {
  printf("Output size: %d\n", writer.size);
}

לשימוש מתקדם יותר ב-API ובמבנה, מומלץ לחפש במסמכים הזמינים בכותרת webp/encode.h. קריאה של הקוד לדוגמה examples/cwebp.c יכולה להיות שימושית כדי לגלות פרמטרים בשימוש נמוך יותר.