简介
在iOS原生的图片压缩算法中,系统提供了PNG和JPEG两种压缩方式(NSData),用来进行网络传输。
PNG一般用在图标中;稍微大一点图片,一般都会采用JPEG格式。
问题
就算采用JPEG方式压缩,系数缩小到0.5,仍然感觉图片太大。如果把系数缩小到0.3,那么图片质量就不可接受了,会出现红斑。所以,希望在保证图片质量的前提下,缩小图片的大小。
WebP
搜索一番,发现还真有比JPEG更好的压缩方式。这个格式就是webp。
WebP 极限压缩及ios实现

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

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

压缩效果明显
- JPEG压缩2M多

- 这个webp的库压缩后只有77K,相差几十倍啊

问题:图片严重失真
- 压缩前的原图

- 压缩后的图片颜色严重失真

纠结
-
压缩效率真的很惊人;
-
颜色失真太严重;
-
纠结之后,最后选择放弃;
-
虽然是大神写的,也只能放弃不用;
实现2:
- 在网上搜索,发现一篇和我们现在的需求非常相近的文章,赶紧收藏。
- 文章中提到的第三方库有自己的网站,在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'

代码样例
// 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;
- 效果对比:


- 图片质量:(系数0.5)
原图:

WebP压缩后:

看上去差不多,效果不错。
小结
经过对比,可以看出YYImage优势明显,使用起来也很方便。
网友评论