Tài liệu về API WebP

Phần này mô tả API cho bộ mã hoá và bộ giải mã đi kèm 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ụ: bật nền tảng Unix, tệp tiêu đề sau đây sẽ được sao chép vào /usr/local/include/webp/.

decode.h
encode.h
types.h

Các thư viện này nằm trong các thư mục thư viện thông thường. Phương thức tĩnh và thư viện động nằm 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 rằng bạn có các tệp thư viện và tiêu đề được cài đặt như được 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 và truy xuất chiều rộng của hình ảnh và chiều cao. Con trỏ *width*height có thể được truyền NULL nếu được coi là không liên quan.

Thuộc tính phương thức nhập

dữ liệu
Con trỏ sang dữ liệu hình ảnh WebP
kích_ thước_dữ_liệu
Đây là kích thước của khối bộ nhớ mà 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 đối tượng từ luồng bit. *features cấu trúc chứa thông tin thu thập được từ luồng bit:

Thuộc tính phương thức nhập

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

Giá trị trả về

VP8_STATUS_OK
Trường hợp các tính nă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 các 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 được trỏ đến bằng data.

  • 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 thứ tự [a0, r0, g0, b0, a1, r1, g1, b1, ...].
  • WebPDecodeBGRA trả về các mẫu hình ảnh BGRA theo thứ tự [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 theo thứ tự [b0, g0, r0, b1, g1, r1, ...].

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*) được các hàm này trả về bằng WebPFree().

Thuộc tính phương thức nhập

dữ liệu
Con trỏ sang dữ liệu hình ảnh WebP
kích_ thước_dữ_liệu
Đây là kích thước của khối bộ nhớ mà 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 từ 1 đến 16383.
độ cao
Giá trị số nguyên. Phạm vi hiện bị giới hạn từ 1 đến 16383.

Giá trị trả về

uint8_t*
Con trỏ để giải mã các mẫu hình ảnh WebP ở định dạng RGBA/ARGB/BGRA/RGB/BGR tuyến tính đơn đặt hàng 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 có sẵn trong vùng đệm này được biểu thị bằng output_buffer_size. Nếu bộ nhớ này chưa đủ (hoặc đã xảy ra lỗi), NULL được trả về. Nếu không, output_buffer được trả về để thuận tiện.

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

Thuộc tính phương thức nhập

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

Giá trị trả về

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

API Giải mã nâng cao

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

Giải mã WebP có hai biến thể, đó là giải mã hình ảnh đầy đủ và giải mã gia tăng giải mã qua các vùng đệm đầu vào nhỏ. Người dùng có thể tuỳ ý cung cấp vùng đệm bộ nhớ để giải mã hình ảnh. Mã mẫu sau đây sẽ giúp bạn tìm hiểu 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 chạy 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 WebPDecoderConfig cấu trúc:

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

Nếu muốn, bạn có thể đọc các tính năng luồng bit vào config.input, phòng khi chúng tôi cần biết trước. Chẳng hạn như việc biết được thông tin này có thể giúp ích cho bạn liệu bức ảnh có chút trong suốt nào không. Xin lưu ý rằng việc này sẽ cũng phân tích cú pháp tiêu đề của luồng bit và do đó, là một cách hay để biết nếu luồng bit có vẻ giống WebP hợp lệ.

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 vùng đệm đó thay vì dựa vào bộ giải mã để phân bổ. Chúng tôi chỉ cần cung cấp con trỏ cho bộ nhớ cũng như tổng dung lượng của vùng đệm và sải chân của 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ó thể có hai biến thể để giải mã hình ảnh. Chúng tôi có thể giải mã hình ảnh 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 dần hình ảnh khi các byte mới trở nên khả dụng:

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 đú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ý theo cách khác. 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. An toàn khi gọi hàm này ngay cả khi bộ nhớ nằm ngoài và không được phân bổ theo WebPDecode():

WebPFreeDecBuffer(&config.output);

Sử dụng API này, hình ảnh cũng có thể được giải mã 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 mẫu RGBA trong hầu hết các bố cục phổ biến. Các lớp này được khai báo trong webp/encode.h tiêu đề dưới dạng:

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 nằm trong khoảng từ 0 đến 100 và kiểm soát tổn thất và chất lượng trong quá trình nén. Giá trị 0 tương ứng với giá trị thấp có chất lượng và kích thước đầu ra nhỏ, trong khi 100 là mức chất lượng cao nhất và lớn nhất kích thước đầu ra. Sau khi thành công, các byte được nén sẽ được đặt vào *output con trỏ và kích thước tính bằng byte được trả về (nếu không thì 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 *output con trỏ để lấy lại bộ nhớ.

Mảng đầu vào phải là một mảng byte đóng gói (một mảng cho mỗi kênh, như được mong đợi từ 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 để mã hoá không tổn hao, với các 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 (chẳng hạn như các phiên bản có tổn hao) hãy dùng chế độ mặc định của thư viện phần cài đặt. Đối với định dạng không tổn hao, giá trị này có nghĩa là "chính xác" đã bị tắt. Các giá trị RGB trong những vùng trong suốt sẽ được sửa đổi để cải thiện độ nén. Để tránh điều này, hãy sử dụng WebPEncode() rồi đặt WebPConfig::exact thành 1.

API mã hoá nâng cao

nâng cao, bộ mã hoá đi kèm với nhiều tham số mã hoá nâng cao. Chúng có thể hữu ích để cân bằng tốt hơn sự đánh đổi giữa nén hiệu quả và thời gian xử lý. Các tham số này được thu thập trong cấu trúc WebPConfig. Các trường được sử dụng nhiều nhất của 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
};

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

Các mẫu đầu vào phải được gói vào 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 dựa trên giá trị của cờ use_argb.

Cấu trúc này đượ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ó chức năng phát các byte nén khi chúng được cung cấp. Hãy xem ví dụ dưới đây về một người viết trong bộ nhớ. Những người viết khác có thể trực tiếp lưu trữ dữ liệu vào một tệp (xem examples/cwebp.c cho ví dụ như vậy).

Quy trình mã hoá chung để mã hoá bằng API nâng cao 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 tham số nén. Lưu ý rằng bạn có thể sử dụng cùng một cấu hình để nén một số 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 khảo hoặc sao chép. Sau đây là ví dụ về việc phân bổ vùng đệm để lưu giữ các mẫu. Nhưng người dùng có thể dễ dàng thiết lập một "chế độ xem" cho một mục tiêu đã phân bổ mảng mẫu. Hãy 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.

Để chuyển phát các byte được nén, một hook sẽ được gọi mỗi khi các byte mới được sẵn có. Sau đây là một ví dụ đơn giản, trong đó tác giả của bộ nhớ được khai báo trong webp/encode.h. Khởi chạy này có thể cần cho từng ảnh cần nén:

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

Chúng ta hiện đã 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 tài liệu có trong tiêu đề webp/encode.h. Việc đọc mã ví dụ examples/cwebp.c có thể hữu ích để khám phá các tham số ít được sử dụng hơn.