Tài liệu về API WebP

Phần này mô tả API cho bộ mã hoá và bộ giải mã có trong thư viện WebP. Nội dung mô tả API này liên quan đến phiên bản 1.4.0.

Tiêu đề và thư viện

Khi bạn cài đặt libwebp, một thư mục có tên là webp/ sẽ được cài đặt tại vị trí thông thường dành cho nền tảng của bạn. Ví dụ: trên các nền tảng Unix, các tệp tiêu đề sau đây sẽ được sao chép vào /usr/local/include/webp/.

decode.h
encode.h
types.h

Thư viện được đặt trong các thư mục thông thường của thư viện. Thư viện tĩnh và động có trong /usr/local/lib/ trên các nền tảng Unix.

API giải mã đơn giản

Để bắt đầu sử dụng API giải mã, bạn phải đảm bảo đã cài đặt các tệp thư viện và tệp tiêu đề như mô tả ở trên.

Đưa tiêu đề API giải mã vào mã C/C++ của bạn như sau:

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

Hàm này sẽ xác thực tiêu đề hình ảnh WebP, đồng thời truy xuất chiều rộng và chiều cao của hình ảnh. Con trỏ *width*height có thể được chuyển NULL nếu bị cho là không liên quan.

Thuộc tính dữ liệu đầu vào

data
Con trỏ đến dữ liệu hình ảnh WebP
data_size
Đây là kích thước của khối bộ nhớ được data trỏ đến có chứa dữ liệu hình ảnh.

Giá trị trả về

false
Mã lỗi được trả về trong trường hợp (a) lỗi định dạng.
đúng
Khi thành công. *width*height chỉ hợp lệ khi trả về thành công.
chiều rộng
Giá trị số nguyên. Phạm vi được giới hạn từ 1 đến 16383.
độ cao
Giá trị số nguyên. Phạm vi được giới hạn từ 1 đến 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);

Hàm này sẽ truy xuất các tính năng từ luồng bit. Cấu trúc *features chứa thông tin thu thập được từ luồng bit:

Thuộc tính dữ liệu đầu vào

data
Con trỏ đến dữ liệu hình ảnh WebP
data_size
Đây là kích thước của khối bộ nhớ được data trỏ đến có chứa dữ liệu hình ảnh.

Giá trị trả về

VP8_STATUS_OK
Khi các đối tượng được truy xuất thành công.
VP8_STATUS_NOT_ENOUGH_DATA
Khi cần thêm dữ liệu để truy xuất tính năng từ tiêu đề.

Các giá trị lỗi VP8StatusCode bổ sung trong các trường hợp khác.

tính năng
Con trỏ đến cấu trúc 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);

Các hàm này giải mã hình ảnh WebP do data trỏ đến.

  • WebPDecodeRGBA trả về các mẫu hình ảnh RGBA theo thứ tự [r0, g0, b0, a0, r1, g1, b1, a1, ...].
  • WebPDecodeARGB trả về các mẫu hình ảnh ARGB theo đơn đặt hàng [a0, r0, g0, b0, a1, r1, g1, b1, ...].
  • WebPDecodeBGRA trả về các mẫu hình ảnh BGRA theo đơn đặt hàng [b0, g0, r0, a0, b1, g1, r1, a1, ...].
  • WebPDecodeRGB trả về các mẫu hình ảnh RGB theo thứ tự [r0, g0, b0, r1, g1, b1, ...].
  • WebPDecodeBGR trả về các mẫu hình ảnh BGR trong [b0, g0, r0, b1, g1, r1, ...] đơn đặt hàng.

Mã gọi bất kỳ hàm nào trong số này phải xoá vùng đệm dữ liệu (uint8_t*) do các hàm này trả về bằng WebPFree().

Thuộc tính dữ liệu đầu vào

data
Con trỏ đến dữ liệu hình ảnh WebP
data_size
Đây là kích thước của khối bộ nhớ được data trỏ đến có chứa dữ liệu hình ảnh
chiều rộng
Giá trị số nguyên. Phạm vi hiện được giới hạn trong khoảng từ 1 đến 16383.
độ cao
Giá trị số nguyên. Phạm vi hiện được giới hạn từ 1 đến 16383.

Giá trị trả về

uint8_t*
Con trỏ đến các mẫu hình ảnh WebP đã giải mã theo thứ tự tuyến tính RGBA/ARGB/BGRA/RGB/BGR tương ứng.
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);

Các hàm này là biến thể của các hàm ở trên và giải mã hình ảnh trực tiếp vào vùng đệm phân bổ trước output_buffer. Dung lượng lưu trữ tối đa hiện có trong vùng đệm này được biểu thị bằng output_buffer_size. Nếu bộ nhớ này không đủ (hoặc đã xảy ra lỗi), thì NULL sẽ được trả về. Nếu không, output_buffer sẽ được trả về để thuận tiện.

Tham số output_stride chỉ định khoảng cách (tính bằng byte) giữa các đường quét. Do đó, output_buffer_size dự kiến sẽ ít nhất là output_stride * picture - height.

Thuộc tính dữ liệu đầu vào

data
Con trỏ đến dữ liệu hình ảnh WebP
data_size
Đây là kích thước của khối bộ nhớ được data trỏ đến có chứa dữ liệu hình ảnh
output_buffer_size
Giá trị số nguyên. Dung lượng của vùng đệm được phân bổ
output_stride
Giá trị số nguyên. Chỉ định khoảng cách giữa các đường quét.

Giá trị trả về

output_buffer
Con trỏ đến hình ảnh WebP đã giải mã.
uint8_t*
output_buffer nếu hàm thành công; nếu không thì NULL.

API giải mã nâng cao

Tính năng giải mã WebP hỗ trợ một API nâng cao để mang lại khả năng cắt và thay đổi kích thước một cách nhanh chóng, hữu ích trong các môi trường hạn chế về bộ nhớ như điện thoại di động. Về cơ bản, mức sử dụng bộ nhớ sẽ thay đổi theo kích thước của đầu ra, chứ không phải đầu vào khi người dùng chỉ cần xem trước nhanh hoặc một phần được phóng to của một hình ảnh quá lớn. Một số CPU cũng có thể được lưu một cách tình cờ.

Phương thức giải mã WebP có 2 biến thể: giải mã hình ảnh đầy đủ và giải mã tăng dần qua các vùng đệm đầu vào nhỏ. Người dùng có thể tuỳ ý cung cấp một vùng đệm bộ nhớ ngoài để giải mã hình ảnh. Mã mẫu sau đây sẽ đi qua các bước sử dụng API giải mã nâng cao.

Trước tiên, chúng ta cần khởi tạo một đối tượng cấu hình:

#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.

Các tuỳ chọn giải mã được tập hợp trong cấu trúc 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]
};

Bạn có thể đọc các tính năng luồng bit trong config.input trong trường hợp cần biết trước các tính năng đó. Chẳng hạn, bạn có thể biết được hình ảnh có độ trong suốt hay không. Xin lưu ý rằng thao tác này cũng sẽ phân tích cú pháp tiêu đề của luồng bit. Do đó, đây là cách hay để biết liệu luồng bit đó có giống như một luồng WebP hợp lệ hay không.

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

Sau đó, chúng ta cần thiết lập vùng đệm bộ nhớ giải mã trong trường hợp muốn cung cấp trực tiếp thay vì dựa vào bộ giải mã để phân bổ. Chúng ta chỉ cần cung cấp con trỏ đến bộ nhớ cũng như tổng kích thước của vùng đệm và sải bước trên dòng (khoảng cách tính bằng byte giữa các đường quét).

// 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;

Hình ảnh đã sẵn sàng để được giải mã. Có hai biến thể để giải mã hình ảnh. Chúng tôi có thể giải mã hình ảnh trong một lần bằng cách sử dụng:

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

Ngoài ra, chúng ta có thể sử dụng phương thức gia tăng để giải mã dần hình ảnh khi có các byte mới:

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.

Hình ảnh đã giải mã hiện nằm trong config.output (hoặc nói đúng hơn là trong config.output.u.RGBA trong trường hợp này, vì hệ màu đầu ra được yêu cầu là MODE_BGRA). Hình ảnh có thể được lưu, hiển thị hoặc xử lý hình ảnh. Sau đó, chúng ta chỉ cần lấy lại bộ nhớ được phân bổ trong đối tượng của cấu hình. Bạn có thể gọi hàm này ngay cả khi bộ nhớ nằm ngoài và không được WebPDecode() phân bổ:

WebPFreeDecBuffer(&config.output);

Khi sử dụng API này, hệ thống cũng có thể giải mã hình ảnh thành các định dạng YUV và YUVA bằng cách sử dụng MODE_YUVMODE_YUVA tương ứng. Định dạng này còn được gọi là Y'CbCr.

API mã hoá đơn giản

Một số hàm rất đơn giản được cung cấp để mã hoá các mảng của các mẫu RGBA trong các bố cục phổ biến nhất. Các API này được khai báo trong tiêu đề webp/encode.h như sau:

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);

Hệ số chất lượng quality_factor dao động từ 0 đến 100 và kiểm soát tỷ lệ mất mát cũng như chất lượng trong quá trình nén. Giá trị 0 tương ứng với chất lượng thấp và kích thước đầu ra nhỏ, trong khi 100 là chất lượng cao nhất và kích thước đầu ra lớn nhất. Sau khi thành công, các byte nén sẽ được đặt vào con trỏ *output và kích thước tính bằng byte sẽ được trả về (nếu không sẽ trả về 0, trong trường hợp không thành công). Phương thức gọi phải gọi WebPFree() trên con trỏ *output để lấy lại bộ nhớ.

Mảng đầu vào phải là một mảng byte được đóng gói (một mảng cho mỗi kênh, như mong đợi theo tên hàm). stride tương ứng với số byte cần thiết để chuyển từ hàng này sang hàng tiếp theo. Ví dụ: bố cục BGRA là:

Có các hàm tương đương cho phương thức mã hoá không tổn hao, kèm theo chữ ký:

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);

Lưu ý rằng các hàm này, như các phiên bản có tổn hao, sẽ sử dụng chế độ cài đặt mặc định của thư viện. Đối với định dạng không tổn hao, giá trị này có nghĩa là thuộc tính "chính xác" bị tắt. Các giá trị RGB trong các vùng trong suốt sẽ được sửa đổi để cải thiện độ nén. Để tránh trường hợp này, hãy sử dụng WebPEncode() và đặt WebPConfig::exact thành 1.

API mã hoá nâng cao

Về sau, bộ mã hoá đi kèm với nhiều thông số mã hoá nâng cao. Chúng có thể hữu ích để cân bằng hiệu quả hơn giữa hiệu suất nén và thời gian xử lý. Các tham số này được tập hợp trong cấu trúc WebPConfig. Các trường được sử dụng nhiều nhất trong cấu trúc này là:

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
};

Xin lưu ý rằng bạn có thể truy cập vào hầu hết các tham số này để thử nghiệm bằng cách sử dụng công cụ dòng lệnh cwebp.

Các mẫu đầu vào phải được gói trong cấu trúc WebPPicture. Cấu trúc này có thể lưu trữ các mẫu đầu vào ở định dạng RGBA hoặc YUVA, tuỳ thuộc vào giá trị của cờ use_argb.

Cấu trúc được sắp xếp như sau:

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;
};

Cấu trúc này cũng có một hàm để phát ra các byte nén khi chúng được tạo sẵn. Hãy xem ví dụ dưới đây về người ghi trong bộ nhớ. Những người viết khác có thể lưu trữ trực tiếp dữ liệu vào một tệp (xem examples/cwebp.c để biết ví dụ như vậy).

Quy trình chung cho việc mã hoá bằng API nâng cao sẽ có dạng như sau:

Trước tiên, chúng ta cần thiết lập một cấu hình mã hoá chứa các thông số nén. Lưu ý rằng bạn có thể sử dụng cùng một cấu hình để nén nhiều hình ảnh sau đó.

#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)

Sau đó, các mẫu đầu vào cần được tham chiếu vào WebPPicture bằng cách tham chiếu hoặc sao chép. Dưới đây là ví dụ phân bổ vùng đệm để lưu giữ các mẫu. Tuy nhiên, bạn có thể dễ dàng thiết lập "chế độ xem" cho một mảng mẫu đã phân bổ. Xem hàm 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.

Để phát ra các byte được nén, một hook sẽ được gọi mỗi khi có sẵn byte mới. Dưới đây là một ví dụ đơn giản với trình ghi bộ nhớ được khai báo trong webp/encode.h. Có thể quá trình khởi chạy này sẽ cần thiết để mỗi ảnh nén được:

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

Bây giờ, chúng ta đã sẵn sàng nén các mẫu đầu vào (và giải phóng bộ nhớ sau đó):

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);
}

Để sử dụng API và cấu trúc nâng cao hơn, bạn nên xem tài liệu có trong tiêu đề webp/encode.h. Việc đọc mã ví dụ examples/cwebp.c có thể chứng minh hữu ích cho việc phát hiện các tham số ít được sử dụng.