WebP API 文档

本部分介绍了 WebP 库中包含的编码器和解码器的 API。此 API 说明适用于版本 1.6.0。

头文件和库

当您安装 libwebp 时,系统会在您平台的典型位置安装一个名为 webp/ 的目录。例如,在 Unix 平台上,以下头文件会被复制到 /usr/local/include/webp/

decode.h
encode.h
types.h

这些库位于常规库目录中。静态库和动态库位于 Unix 平台上的 /usr/local/lib/ 中。

Simple Decoding API

如需开始使用解码 API,您必须确保已安装库和头文件,如上文所述。

在 C/C++ 代码中包含解码 API 标头,如下所示:

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

此函数将验证 WebP 图片标头并检索图片宽度和高度。如果认为指针 *width*height 不相关,则可以传递 NULL

输入属性

数据
指向 WebP 图片数据的指针
data_size
这是 data 所指向的内存块的大小,其中包含图片数据。

返回

false
出现格式设置错误时返回的错误代码。
true
成功时。*width*height 仅在成功返回时有效。
width
整数值。范围限制为 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);

此函数将从比特流中检索特征。*features 结构体填充了从比特流收集的信息:

输入属性

数据
指向 WebP 图片数据的指针
data_size
这是 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);

这些函数用于解码 data 所指向的 WebP 图片。

  • WebPDecodeRGBA[r0, g0, b0, a0, r1, g1, b1, a1, ...] 顺序返回 RGBA 图像样本。
  • WebPDecodeARGB 会按 [a0, r0, g0, b0, a1, r1, g1, b1, ...] 顺序返回 ARGB 图像样本。
  • WebPDecodeBGRA 会按 [b0, g0, r0, a0, b1, g1, r1, a1, ...] 顺序返回 BGRA 图像样本。
  • WebPDecodeRGB 会按 [r0, g0, b0, r1, g1, b1, ...] 顺序返回 RGB 图像样本。
  • WebPDecodeBGR 会按 [b0, g0, r0, b1, g1, r1, ...] 顺序返回 BGR 图像样本。

调用上述任一函数的代码必须使用 WebPFree() 删除这些函数返回的数据缓冲区 (uint8_t*)

输入属性

数据
指向 WebP 图片数据的指针
data_size
这是 data 所指向的包含图片数据的内存块的大小
width
整数值。目前,该范围限制为 1 到 16383。
高度
整数值。目前,该范围限制为 1 到 16383。

返回

uint8_t*
指向线性 RGBA/ARGB/BGRA/RGB/BGR 顺序的解码 WebP 图片样本的指针。
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_size
这是 data 所指向的包含图片数据的内存块的大小
output_buffer_size
整数值。已分配缓冲区的大小
output_stride
整数值。指定扫描线之间的距离。

返回

output_buffer
指向解码后的 WebP 图片的指针。
uint8_t*
如果函数成功,则为
output_buffer;否则为 NULL

高级解码 API

WebP 解码支持高级 API,可实现实时裁剪和重新缩放,这在内存受限的环境(如手机)中非常有用。基本上,内存用量会随输出大小而变化,而不是随输入大小而变化,前提是用户只需要快速预览或放大查看原本过大的图片的一部分。顺便说一句,还可以节省一些 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]
};

或者,也可以将位流特征读入 config.input,以便我们提前了解这些特征。例如,了解图片是否具有任何透明度会很有用。请注意,此函数还会解析位流的标头,因此是了解位流是否看起来像有效的 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 中,因为请求的输出颜色空间为 MODE_BGRA)。图片可以保存、显示或以其他方式处理。 之后,我们只需要回收在配置对象中分配的内存。 即使内存是外部内存且不是由 WebPDecode() 分配的,也可以安全地调用此函数:

WebPFreeDecBuffer(&config.output);

使用此 API,还可以分别使用 MODE_YUVMODE_YUVA 将图片解码为 YUV 和 YUVA 格式。此格式也称为 Y'CbCr

Simple Encoding 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)。调用者必须对 *output 指针调用 WebPFree() 以回收内存。

输入数组应为打包的字节数组(每个渠道一个字节,如函数名称所示)。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);

请注意,这些函数与有损版本一样,使用库的默认设置。对于无损压缩,这意味着“精确”处于停用状态。系统会修改透明区域中的 RGB 值,以提高压缩率。为避免这种情况,请使用 WebPEncode() 并将 WebPConfig::exact 设置为 1

Advanced Encoding 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 有助于发现不太常用的参数。