美文网首页IOS开发iOS开发笔记
关于WebP在iOS中的应用

关于WebP在iOS中的应用

作者: shiyueZ | 来源:发表于2018-07-25 09:32 被阅读0次

介绍

  是一种同时提供了有损压缩无损压缩图片文件格式,派生自图像编码格式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^!!  觉得有用的朋友麻烦点个赞咯,一起学习,一起成长!

相关文章

网友评论

    本文标题:关于WebP在iOS中的应用

    本文链接:https://www.haomeiwen.com/subject/kabumftx.html