webp格式图片
webp格式图片是google推出的,相比jpg png有着巨大的优势,同样质量的图片webp格式的图片占用空间更小,在像电商这样图片比较多的App中,使用webp格式图片会很有优势。
引言
很早之前,我们的项目中就已经采用了webp格式,但是由于webView本身并不能解析webp格式,所以我们基于webView的文章详情页就无法使用到这项优化。
那么有没有什么办法能实现呢?当然是有的。
在开始技术讲解之前需要先说明,本文的技术方案,是基于本项目的情况:文章的正文大部分通过接口直接获取到,通过在客户端本地进行html正文组装,最后通过webView的loadHTMLString方法进行加载显示。普通的图片可以通过转换链接得到webp服务器获取到相应的webp版的图片。
本项目中,图片缓存使用了SDWebImage,并且开启了webp支持功能,那么我们对详情页webView的处理也会基于此来实现。
通过思考,方案其实还是比较明确的,就是替换html中图片链接,通过客户端下载webp图片,然后在通过js刷新出页面上的下完的图片,但实际开发中也遇到了一些坑,比如:
HTML解析库的setAttributeNamed不能增加属性 webp服务器图片下载后的默认缓存时gif不能正常存储 下载完的图片不能实时通过js更改src为本地文件地址加载出来最终的技术实现:
1.对下载回来的html内容进行处理,获取所有图片链接,并进行webp链接处理转换
对html内容的解析处理我使用的是Objective-C-HMTL-Parser,但是该库已经多年不维护,这里有我fork后进行部分优化调整的版本:https://www.easck.com//给img标签中增加一个叫osrc的属性,便于后续处理 setAttributeNamed(inputNode->_node, "osrc", [newSrc cStringUsingEncoding:NSUTF8StringEncoding]); } htmlContent = [NSMutableString stringWithString:parser.doc.rawContents]; } @catch (NSException *exception) { } @finally { [webView loadHTMLString:htmlContent baseURL:baseUrl]; }
2.用原生方法下载webp图片,缓存到本地
下载之后会存储为jpg或png格式,这样就可以被webView进行本地加载,但是需要注意gif的存储特殊处理。
另外通过实验,直接通过js无法实时更新下载到本地的图片,只好通过图片的base64encode数据加载方式实现。
具体代码如下:
- (void)webViewDidFinishLoad:(UIWebView *)web {
//处理webp格式加载
[_webpImageUrlDic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
if([obj isEqualToString:key]){//说明这图没有缓存,还需要下载
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:obj] options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
if (image&&finished) {
NSString *js;
NSRange range = [[obj lowercaseString] rangeOfString:@".gif"];//检查是否是gif
BOOL isGif = (range.location != NSNotFound);
if (!isGif) {
[[SDImageCache sharedImageCache] storeImage:image forKey:obj];
NSString *base64 = [UIImageJPEGRepresentation(image,1) base64EncodedStringWithOptions:0];
js = [NSString stringWithFormat:@"replaceWebPImg('%@','data:image/jpeg;base64,%@')",key,base64];
}else{//gif的图片如果直接存储,会变成jpg从而失去动画,因此要特殊处理
[[SDImageCache sharedImageCache] storeImage:image recalculateFromImage:false imageData:data forKey:key toDisk:true];
NSString *base64 = [data base64EncodedStringWithOptions:0];
js = [NSString stringWithFormat:@"replaceWebPImg('%@','data:image/gif;base64,%@')",key,base64];
}
[NSThread excuteInMainThread:^{
[webView stringByEvaluatingJavaScriptFromString:js];
} async:false];
}
}];
} else {//缓存中存在,那么直接加载吧
NSString *js;
NSRange range = [[obj lowercaseString] rangeOfString:@".gif"];//检查是否是gif
NSData* data = [NSData dataWithContentsOfFile:[key stringByReplacingOccurrencesOfString:@"file://" withString:@""]];
NSString *base64 = [data base64EncodedStringWithOptions:0];
BOOL isGif = (range.location != NSNotFound);
if (!isGif) {
js = [NSString stringWithFormat:@"replaceWebPImg('%@','data:image/jpeg;base64,%@')",obj,base64];
}else{
js = [NSString stringWithFormat:@"replaceWebPImg('%@','data:image/gif;base64,%@')",obj,base64];
}
[NSThread excuteInMainThread:^{
[webView stringByEvaluatingJavaScriptFromString:js];
} async:false];
}
}];
}










