介绍
是一种同时提供了有损压缩与无损压缩的图片文件格式,派生自图像编码格式VP8 。由谷歌于2010年推出的新一代图片格式,在压缩方面比当前JPEG格式更优越,这种格式的主要优势在于高效率。“在质量相同的情况下,WebP格式图像的体积要比JPEG格式图像小40%。谷歌浏览器已经支持webp格式,Opera在版本号Opera11.10后也增加了支持,然而火狐和ie暂时还不支持webp格式,可以采用flash插件来显示webp,当然这样会耗费一些性能。
美中不足的是,WebP格式图像的编码时间“比JPEG格式图像长8倍”。
分析人士认为,尽管WebP格式尚未像JPEG格式那样,得到各种软硬件的广泛支持,但谷歌推广这一格式的优势在于Chrome浏览器。这款谷歌开发的浏览器的市场份额已达10%以上。
苹果的Safri还没有兼容这种格式,所以如果UIWebView里面含有WebP的图片的话,就会显示不出来(但是我们可以通过NSUrlProtocol来做处理)。如果要在APP中使用得话,我们需要引入SDWebImage这个第三方库。
SDWebImage使用WebP
[imageView sd_setImageWithURL:[NSURL URLWithString:图片路径]
placeholderImage:[UIImage imageNamed:@"默认图片"]
completed:^(UIImage *image, NSError *error,
SDImageCacheType cacheType, NSURL *imageURL) {
//do something }];
深入研究它是怎么实现的:
在SDWebImageDownloaderOperation这个类中,该类继承NSOperation,主要使用NSUrlSession来下载网络图片,我们来看它下载完成的委托方法:
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
我们截取部分代码块来集中分析一下:
UIImage *image = [UIImage sd_imageWithData:self.imageData];
调试进去:
UIImage *image;
NSString *imageContentType = [NSData sd_contentTypeForImageData:data];//根据数据流的前8位来判断图片类型
if([imageContentType isEqualToString:@"image/gif"]) {
image = [UIImage sd_animatedGIFWithData:data];
}
#ifdef SD_WEBP
else if([imageContentType isEqualToString:@"image/webp"]) {
image = [UIImage sd_imageWithWebPData:data];//将WebP解码成相应的格式(可能是jpg,png等)
}
#endif
else {
image = [[UIImage alloc] initWithData:data];
UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data];
if(orientation != UIImageOrientationUp) {
image = [UIImage imageWithCGImage:image.CGImage
scale:image.scale
orientation:orientation];
}
}
我们来说下sd_contentTypeForImageData 这个方法,如下:
+ (NSString *)sd_contentTypeForImageData:(NSData *)data {
uint8_t c;
[data getBytes:&c length:1];
switch (c) {
case 0xFF:
return @"image/jpeg";
case 0x89:
return @"image/png";
case 0x47:
return @"image/gif";
case 0x49:
case 0x4D:
return @"image/tiff";
case 0x52:
// R as RIFF for WEBP
if ([data length] < 12) {
return nil;
}
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
return @"image/webp";
}
return nil;
}
return nil;
}
里面的uint8_t就是取NSData的前8位,因为图片变换成NSData后,是使用得ASCII码来表示的,每种图片都含有固定的头信息块。
png是:89 50 4E 47 0D 0A 1A 0A
bmp是:42 4D
jpg是:FF D8 FF
webp是:52 49 46 46 中间4个字符不定 57 45 42 50(翻译过来就是:RIFF 其他4个字符 WEBP)
注意:SDWebImage在对WebP做存储的时候,存的是未解码的NSData,而不是解码后的NSData,如下代码:
SDWebImageManager 里面的
if (options & SDWebImageRefreshCached && image && !downloadedImage) {
// Image refresh hit the NSURLCache cache, do not call the completion block
}
else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage))) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
UIImage *transformedImage = [self transformDownloadedImage:downloadedImage imageData:data withURL:url]; //存储以前,是否要将nsdata转换为其他格式的图片对象
if (transformedImage && finished) {
BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage];
[self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:(imageWasTransformed ? nil : data) forKey:key toDisk:cacheOnDisk];
}
dispatch_main_sync_safe(^{
if (strongOperation && !strongOperation.isCancelled) {
completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
});
}
else {
if (downloadedImage && finished) {
[self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk]; //WebP的存储走的是这一步
}
dispatch_main_sync_safe(^{
if (strongOperation && !strongOperation.isCancelled) {
completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url);
}
});
}
里面提供了一个委托:
UIImage *transformedImage = [self transformDownloadedImage:downloadedImage imageData:data withURL:url];
可能考虑到WebP的解码会耗费一些时间,测试发现,120k左右的WebP,解码会耗时30ms左右,所以提供一个委托,可以选择将WebP的NSData转换为png或者jpg之后,存储到内存,再存储到磁盘。
==================一条迷人的分割线================
最后转载@KevinMK一个在webView中实用webP的文章,该文章提供了两种方法实现webView中加载webP格式,希望大家喜欢!!!
喜欢请戳这里^oo^!! 觉得有用的朋友麻烦点个赞咯,一起学习,一起成长!
网友评论