本部分介绍了 WebP 库中包含的编码器和解码器的 API。此 API 说明适用于版本 1.4.0。
头文件和库
当您安装 libwebp
时,名为 webp/
的目录将安装到您的平台的典型位置。例如,在 Unix 平台上,以下头文件将复制到 /usr/local/include/webp/
。
decode.h
encode.h
types.h
这些库位于常规库目录中。在 Unix 平台上,静态库和动态库位于 /usr/local/lib/
中。
简单解码 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
指针。
输入属性
- data
- 指向 WebP 图片数据的指针
- data_size
- 这是包含图片数据的
data
所指向的内存块的大小。
返回
- false
- 发生 (a) 格式错误时返回的错误代码。
- 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);
此函数将从比特流中检索特征。*features
结构中填充了从比特流收集的信息:
输入属性
- data
- 指向 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*)
。
输入属性
- data
- 指向 WebP 图片数据的指针
- data_size
- 这是包含图片数据的
data
所指向的内存块的大小 - 宽度
- 整数值。该范围目前限定在 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
。
输入属性
- data
- 指向 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_YUV
和 MODE_YUVA
将图片解码为 YUV 和 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)。调用方必须对 *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
。
高级编码 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
有助于发现不太常用的参数。