前几天有个需求是需要把一些 JPG 图片转换成 WebP 然后放到客户端里播放动图,主要是想享受 WebP 格式带来的压缩率,生成更小的图片文件,节省带宽和下载时间。

webpmux 是什么?

webpmux 是 Google 为其 WebP 出得附属配套工具,专门用来操作 WebP 动图,可以从 WebP 动图里抽出每一帧,也可以从一批图像帧合成成一张 WebP 动图,同时也支持设定循环次数、背景颜色,每一帧的播放时长、暂停时间等等。

为什么解不开?

由于 webpmux 的 file_i +di[+xi+yi[+mi[bi]]] 参数 BLEND 项默认为 +b (BLEND) 所以导致我们生成的 WebP 动图用 SDWebImage 解析不出来。

因为 SDWebImage/UIImage+WebP.m 中判断如果当前帧 为 WEBP_MUX_BLEND 则用 sd_blendWebpImageWithOriginImage 解,否则用 sd_rawWepImageWithData 方法

    ...
    do {
        UIImage *image;
        if (iter.blend_method == WEBP_MUX_BLEND) {
            image = [self sd_blendWebpImageWithOriginImage:[images lastObject] iterator:iter];
        } else {
            image = [self sd_rawWepImageWithData:iter.fragment];
        }
        
        if (!image) {
            continue;
        }
        
        [images addObject:image];
        duration += iter.duration / 1000.0f;
        
    } while (WebPDemuxNextFrame(&iter));
    ...

sd_blendWebpImageWithOriginImage 又需要取到上一帧做 blend 叠加,由于第一帧被指定成了 BLEND,所以导致后面所有帧都解不出来。

+ (nullable UIImage *)sd_blendWebpImageWithOriginImage:(nullable UIImage *)originImage iterator:(WebPIterator)iter {
    if (!originImage) {
        return nil;
    }
    ...
}

解决办法

解决办法就是显示指定 webpmux 的 BLEND 参数为 -b (NO_BLEND),让第一帧不使用混合模式,SDWebImage 就能正确解析了。

webpmux -frame 0.webp +100+0+0+0-b \
  -frame 1.webp +100+0+0+0-b \
  -frame 2.webp +100+0+0+0-b \
  -frame 3.webp +100+0+0+0-b \
  -o anim.webp

另外 YYWebImage 的 WebP 解码方式好像是有些不太一样,没有细看,所以用 YY 应该是没问题的。