使用cwebp/libwebp获取动画WebP完整渲染帧的方法
问题描述
提取动画WebP文件独立帧时,直接对单帧分片调用解码接口获得的结果存在帧尺寸不一致、部分帧携带alpha通道的问题,原有实现代码如下:
WebPData rawData = { webpData.data() , webpData.size() }; struct WebPDemuxer* dmuxer = WebPDemux(&rawData); int frame_idx = 1; WebPIterator iter; uint8_t* decode_data; while (true) { WebPDemuxGetFrame(dmuxer, frame_idx, &iter); decode_data = WebPDecodeBGRA(iter.fragment.bytes, iter.fragment.size, &width, &height); if (decode_data == NULL) break; //do something with decode_data WebPDemuxReleaseIterator(&iter); frame_idx++; }
目标是实现类似ImageMagick coalesce选项的效果,获取统一尺寸的完整渲染帧,而非分片存储的增量帧。
实现方案
cwebp是WebP格式的官方编码工具,无法直接用来解码提取帧,代码层面可以通过libwebp官方库实现coalesce效果。动画WebP默认存储的是增量压缩的帧分片,单帧分片仅记录和前一帧存在差异的区域,自带绘制偏移、混合规则、处置规则参数,直接解码单帧分片自然会出现尺寸不统一、内容不完整的问题。有两种可行实现方式:
- 手动合成帧
- 调用
WebPDemuxGetI接口传入WEBP_FF_CANVAS_WIDTH、WEBP_FF_CANVAS_HEIGHT参数,获取动画全局画布的统一宽高,提前分配对应尺寸的帧缓冲区作为渲染画布,初始填充背景色。 - 遍历每帧时先将当前帧分片解码到临时缓冲区,读取迭代器中携带的
x_offset、y_offset、blend_method、dispose_method参数。 - 按照参数规则将临时缓冲区的帧内容绘制到全局画布对应位置,处理alpha混合、区域覆盖逻辑,绘制完成后全局画布的内容就是当前时刻的完整渲染帧。
- 处理完当前帧后按照
dispose_method规则更新画布状态,供下一帧合成使用。如果不需要alpha通道,可在输出帧时直接丢弃alpha通道,或初始化画布时使用不透明背景、混合时强制alpha值为255。
- 调用
- 调用内置动画解码接口(推荐)
libwebp已经提供了封装好的动画解码接口WebPAnimDecoder,内置完整的帧合成逻辑,默认输出全尺寸的完整渲染帧,无需手动处理偏移、混合、处置逻辑,示例代码如下:
WebPAnimDecoderOptions dec_opt; WebPAnimDecoderOptionsInit(&dec_opt); // 如需无alpha通道的帧,可将color_mode设置为MODE_BGR dec_opt.color_mode = MODE_BGRA; WebPAnimDecoder* dec = WebPAnimDecoderNew(&rawData, &dec_opt); WebPAnimInfo anim_info; WebPAnimDecoderGetInfo(dec, &anim_info); // anim_info.canvas_width、anim_info.canvas_height 即为所有输出帧的统一尺寸 uint8_t* frame_buf; int timestamp; while (WebPAnimDecoderHasMoreFrames(dec)) { WebPAnimDecoderGetNext(dec, &frame_buf, ×tamp); // frame_buf指向的内存即为合成完成的全尺寸完整帧,可直接处理 } WebPAnimDecoderDelete(dec);
该接口输出的帧效果和ImageMagick coalesce选项效果完全一致,所有帧尺寸统一,不会出现分片帧尺寸不一的问题。
内容的提问来源于stack exchange,提问作者user8624414
相关产品推荐
相关产品推荐

