Webp压缩实践 2022-11-10 周四

简介

在iOS原生的图片压缩算法中,系统提供了PNG和JPEG两种压缩方式(NSData),用来进行网络传输。
PNG一般用在图标中;稍微大一点图片,一般都会采用JPEG格式。

问题

就算采用JPEG方式压缩,系数缩小到0.5,仍然感觉图片太大。如果把系数缩小到0.3,那么图片质量就不可接受了,会出现红斑。所以,希望在保证图片质量的前提下,缩小图片的大小。

WebP

搜索一番,发现还真有比JPEG更好的压缩方式。这个格式就是webp。
WebP 极限压缩及ios实现

企业微信截图_78bfb084-5771-4ccd-8bad-e2f91e0ec24d.png

实现1

既然webp这么好,那么就试一试。当然,不会真的像上面的文章写的那样自己去写编码方式。找第三方库的实现,发现还真有。

WebPImageSerialization

企业微信截图_ea367e50-2622-445f-ac19-435c10c336f4.png

集成

集成很简单,添加一个framework和两个文件就好。使用也很方便。参考一下提供的例子就明白了。

企业微信截图_67ab175f-cac4-42ef-b537-2b9c56beb0b8.png

压缩效果明显

  • JPEG压缩2M多
企业微信截图_be5fc988-1f55-4116-8e99-38dabc4f9746.png
  • 这个webp的库压缩后只有77K,相差几十倍啊
企业微信截图_4bccfeb7-9514-4bcc-9af9-df0c09e46d7a.png

问题:图片严重失真

  • 压缩前的原图
压缩前.png
  • 压缩后的图片颜色严重失真
压缩后.png

纠结

  • 压缩效率真的很惊人;

  • 颜色失真太严重;

  • 纠结之后,最后选择放弃;

  • 虽然是大神写的,也只能放弃不用;

实现2:

  • 在网上搜索,发现一篇和我们现在的需求非常相近的文章,赶紧收藏。

关于iOS中显示WEBP图像的学习记录

  • 文章中提到的第三方库有自己的网站,在gitHub上也能看到。至少看起来还不错。

iOS-WebP 网站

iOS-WebP gitHub

  • 集成问题

手动集成遇到困难,demo中用到的.a文件不好处理。用pod集成,版本号要去掉;并且编译不同过。 出现 Multiple commands produce问题,按照相关文章修改,没有作用。

  • API不友好
    虽然说webp的压缩比JPEG要耗时,但是给block类型的API是没有必要的。就算集成成功,用起来也不方便。
+ (void)imageToWebP:(UIImage *)image quality:(CGFloat)quality alpha:(CGFloat)alpha preset:(WebPPreset)preset
    completionBlock:(void (^)(NSData *result))completionBlock
       failureBlock:(void (^)(NSError *error))failureBlock;

+ (void)imageWithWebP:(NSString *)filePath
      completionBlock:(void (^)(UIImage *result))completionBlock
         failureBlock:(void (^)(NSError *error))failureBlock;
  • 小结:决定放弃不用。

实现3:YYImage

YYImage中包含webp的编码和解码,真是意外之喜。

安装

  • YY系列都支持CocoaPods,真的很方便

  • webp有额外的组件,需要多加一行

  • Pod命令添加webp

pod 'YYImage'
pod 'YYImage/WebP'
企业微信截图_009acc1e-a0b7-45d9-b25c-fed5692a4210.png

代码样例

// Encode animated image:
YYImageEncoder *webpEncoder = [[YYImageEncoder alloc] initWithType:YYImageTypeWebP];
webpEncoder.loopCount = 5;
[webpEncoder addImage:image0 duration:0.1];
[webpEncoder addImage:image1 duration:0.15];
[webpEncoder addImage:image2 duration:0.2];
NSData webpData = [webpEncoder encode];
  • 例子代码是把3张图片编码为webp动图。我们这里只要一张就好,不需要动图。

样例代码中没有quality参数,为什么?

  • 在初始化中,WebP格式图片给了个默认值0.8,所以可以不给

  • 这个初始化代码中,以NSLog的方式提示WebP需要额外安装组件

- (instancetype)initWithType:(YYImageType)type {
    if (type == YYImageTypeUnknown || type >= YYImageTypeOther) {
        NSLog(@"[%s: %d] Unsupported image type:%d",__FUNCTION__, __LINE__, (int)type);
        return nil;
    }
    
#if !YYIMAGE_WEBP_ENABLED
    if (type == YYImageTypeWebP) {
        NSLog(@"[%s: %d] WebP is not available, check the documentation to see how to install WebP component: https://github.com/ibireme/YYImage#installation", __FUNCTION__, __LINE__);
        return nil;
    }
#endif
    
    self = [super init];
    if (!self) return nil;
    _type = type;
    _images = [NSMutableArray new];
    _durations = [NSMutableArray new];

    switch (type) {
        case YYImageTypeJPEG:
        case YYImageTypeJPEG2000: {
            _quality = 0.9;
        } break;
        case YYImageTypeTIFF:
        case YYImageTypeBMP:
        case YYImageTypeGIF:
        case YYImageTypeICO:
        case YYImageTypeICNS:
        case YYImageTypePNG: {
            _quality = 1;
            _lossless = YES;
        } break;
        case YYImageTypeWebP: {
            _quality = 0.8;
        } break;
        default:
            break;
    }
    
    return self;
}

单张图片编码接口

  • 例子代码给的是把多张图片编码为动图;暂时还没有这个需求

  • 单张图片的编码,提供了一个方便接口

/**
 Convenience method to encode single frame image.
 @param image   The image.
 @param type    The destination image type.
 @param quality Image quality, 0.0~1.0.
 @return The image data, or nil if an error occurs.
 */
+ (nullable NSData *)encodeImage:(UIImage *)image type:(YYImageType)type quality:(CGFloat)quality;
  • 内部调用了初始化接口
+ (NSData *)encodeImage:(UIImage *)image type:(YYImageType)type quality:(CGFloat)quality {
    YYImageEncoder *encoder = [[YYImageEncoder alloc] initWithType:type];
    encoder.quality = quality;
    [encoder addImage:image duration:0];
    return [encoder encode];
}

压缩效果,跟JPEG比较

  • 我们以PNG压缩后的大小为原图大小;

  • JPEG和WebP的压缩系数一样,这里都取0.8;

  • 大小直接除以1000,就当做是K为单位;(进率按1000算是为了简化,1024换算麻烦)

  • 测试代码片段如下:

        // 压缩效果对比
        NSData *pngData = UIImagePNGRepresentation(scaledImage);
        NSInteger pngLength = pngData.length / 1000;
        
        NSData *jpegData = UIImageJPEGRepresentation(scaledImage, compressionQuality);
        NSInteger jpegLength = jpegData.length / 1000;
        
        NSData *webpData = [YYImageEncoder encodeImage:scaledImage type:YYImageTypeWebP quality:compressionQuality];
        NSInteger webpLength = webpData.length / 1000;
  • 效果对比:
企业微信截图_0073ab9c-155f-40b8-ba8a-b33e2bef691a.png
企业微信截图_5127ce19-0296-4f78-bfff-62a447eba036.png
  • 图片质量:(系数0.5)
    原图:
压缩前.png

WebP压缩后:

企业微信截图_ae9c3522-2fc8-4900-bfca-dbf623a35449.png

看上去差不多,效果不错。

小结

经过对比,可以看出YYImage优势明显,使用起来也很方便。

你可能感兴趣的:(Webp压缩实践 2022-11-10 周四)