掌握聚合最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务

移动端如何使用WebP

图片编解码原理

图片编码过程是将 YUV 或者 RGB 像素格式的原始图片编码为压缩格式如 WebP 或者 JPG。图片的解码过程是将压缩格式还原为 YUV 或者 RGB 的原始图片。图片在控件或者屏幕上的渲染展示只能使用原始像素格式,也就是压缩格式的图片必须解码之后才能展示。

WebP

WebP 一种更高效的编码格式,平均大小比 PNG/JPG/ GIF/动态 GIF格式减少 70%对比测试页),且量没有明的差,是其他片格式极佳的替代者。

参考 iOS-WebP 工程,简单了解一下 WebP 的解码过程。

//UIImage+WebP.m

+ (UIImage *)imageWithWebPData:(NSData *)imgData error:(NSError **)error {

    // `WebPGetInfo` weill return image width and height

    int width = 0, height = 0;

    if(!WebPGetInfo([imgData bytes], [imgData length], &width, &height)) {

        ...

        return nil;

    }

    WebPDecoderConfig * config = malloc(sizeof(WebPDecoderConfig));

    if(!WebPInitDecoderConfig(config)) {

        ...

        return nil;

    }

    config->options.no_fancy_upsampling = 1;

    config->options.bypass_filtering = 1;

    config->options.use_threads = 1;

    config->output.colorspace = MODE_RGBA;

    // Decode the WebP image data into a RGBA value array

    VP8StatusCode decodeStatus = WebPDecode([imgData bytes], [imgData length], config);

    if (decodeStatus != VP8_STATUS_OK) {

        ...

        return nil;

    }

    // Construct UIImage from the decoded RGBA value array

    uint8_t *data = WebPDecodeRGBA([imgData bytes], [imgData length], &width, &height);

    ...

    CGImageRef imageRef = CGImageCreate(width, height, 8, 32, 4 * width, colorSpaceRef, bitmapInfo, provider, NULL, YES, renderingIntent);

    UIImage *result = [UIImage imageWithCGImage:imageRef];

    ...

    return result;

}

可见这个解码函数的作用是将 WebP 图片 Data 转换成 UIImage。整个解码功能的实现是依赖于 libwebp 库。解码第一步是调用 WebPGetInfo 函数从 WebpData 中读取图片长宽等信息。第二步是配置解码参数 WebPDecoderConfig ,其中一个重要的参数是 output.colorspace ,即设置解码之后图片的像素格式。示例代码中设置为 MODE_RGBA,从 enum WEBP_CSP_MODE 类型的定义看,解码设置支持多种的 RGB 和 YUV 类型格式。另外的还可以配置图片剪裁、缩放等参数,具体可看考 libwebp API 接下来,第三步将 WebP 数据解码为 RGBA 数据, 第四步将 RGBA 组装为 UIImage。

编码过程与解码相似,需要注意的是 WebP 的有损压缩方式只支持压缩 YUV 数据,如果原始格式是 RGB 可以通过转换为 YUV 数据之后再进行压缩编码。libwebp 也内置了一个转换函数可供使用。

使用 UIImageView 展示 WebP

UIImageView 中使用 WebP 格式图片的最佳实践是依赖 SDWebImage 库。

安装 SDWebImage(支持 WebP):

pod'SDWebImage/WebP'

使用方法:

#import <SDWebImage/UIImageView+WebCache.h>

- (void)viewDidLoad {

    [super viewDidLoad];

    

    //动图类型的 WebP

    NSString *animatedWebpurl = @"https://p.upyun.com/demo/webp/animated-gif/0.gif!/format/webp";

    [self.imageView1 sd_setImageWithURL:[NSURL URLWithString:animatedWebpurl]];

    

    //静图类型的 WebP

    NSString *webpurl = @"https://p.upyun.com/demo/webp/jpg/5.jpg!/format/webp";

    [self.imageView2 sd_setImageWithURL:[NSURL URLWithString:webpurl]];

}

SDWebImage 安装之后内置 libwebp 源码,并在 UIImage+WebP.m 封装实现了 WebP 格式的解码功能。通过 SDWebImage 我们可以非常方便的在 UIImageView 中使用 WebP 格式的图片。

使用 UIWebView 展示 WebP

在以 Native 方式开发的 App 中也会大量使用的 UIWebView 来展示一些简单页面,然而 Safari 及 UIWebView 当前并不支持 WebP 格式。若是想在 UIWebView 中也把图片显示出来,一个解决思路就是:拦截替换。拦截 WebP 图片然后转换为 jpg 或者 png 再交给 UIWebView 进行渲染和展示。

拦截替换 WebP 有两种具体实现方式:

方式 1,通过 UIWebView 代理函数给出的页面加载时机进行 WebP 图片的拦截和替换。这种方式首先要遍历获取 HTML 文档中的所有 WebP 图片链接。获取图片链接过程需要依赖第三方 HTML parser 来解析 HTML 文档,或者通过提前协商好的 HTML 内嵌 js 函数进行通信。在得到所有的 WebP 图片链接之后,将 WebP 下载解码并转换为 jpg 或者其他图片 data,然后再 base64 编码成字符串内嵌到 <img> 标签,让 UIWebView 进行加载。

方式 2,通过 NSURLProtocol 全局拦截和过滤所有 HTTP 请求,将 WebP 数据直接转换为其他格式图片数据,再封装为 response body 吐给原来的 HTTP 请求。代码示例:

//WebP_demo/WebPHttpProxy.m

#pragma mark dataDelegate

 

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{

    NSData *transData = data;

    if ([dataTask.currentRequest.URL.absoluteString hasSuffix:@"webp"]) {

        

        //借用 SDWebImage 中 WebP 的解码方法,将 webp data 转化为 JPEG data

        UIImage *imgData = [UIImage sd_imageWithWebPData:data];

        transData = UIImageJPEGRepresentation(imgData, 1.0f);

    }

    

    [self.client URLProtocol:self didLoadData:transData];

}

这样就可以达到以透明的方式使用 WebP 图片。但是由于 NSURLProtocol 的全局性质,影响范围大,这种方式存在潜在的风险,需要严格的过滤和限制 WebP 请求的拦截。NSURLProtocol 作用的叠加性质,也无法保证与其它第三方代码的兼容。虽然这种方式有很多代码可以参考,本文附带的 demo 也有此种方式的实现,但是在具体工程中使用还需要谨慎和完善。

但,上文已经提到这种全局 NSURLProtocol 拦截的方式存在较大风险。一些网络文章也普遍的引用这种实现方式,但是这段代码是不严谨的,原因在于 NSURLSession 支持流式的 HTTP 请求,或者在 response body 体积比较大的时候,从 didReceiveData 回调回来的一次数据仅仅是整个 response body 的一部分。

iOS 平台使用 SDWebImage 结合又拍云图片处理 API,在原始图片 URL 后面拼接后缀 !/format/webp,不需要其他任何改变,就可以简单快捷的利用 WebP 格式来大幅度减少图片请求流量,提高图片加载体验。

推荐阅读:

1. WebP图片压缩效果对比

2. 移动端APP如何解决WebP兼容

原文来自:SDK.cn

声明:所有来源为“聚合数据”的内容信息,未经本网许可,不得转载!如对内容有异议或投诉,请与我们联系。邮箱:marketing@think-land.com

  • 营运车判定查询

    输入车牌号码或车架号,判定是否属于营运车辆。

    输入车牌号码或车架号,判定是否属于营运车辆。

  • 名下车辆数量查询

    根据身份证号码/统一社会信用代码查询名下车辆数量。

    根据身份证号码/统一社会信用代码查询名下车辆数量。

  • 车辆理赔情况查询

    根据身份证号码/社会统一信用代码/车架号/车牌号,查询车辆是否有理赔情况。

    根据身份证号码/社会统一信用代码/车架号/车牌号,查询车辆是否有理赔情况。

  • 车辆过户次数查询

    根据身份证号码/社会统一信用代码/车牌号/车架号,查询车辆的过户次数信息。

    根据身份证号码/社会统一信用代码/车牌号/车架号,查询车辆的过户次数信息。

  • 风险人员分值

    根据姓名和身份证查询风险人员分值。

    根据姓名和身份证查询风险人员分值。

0512-88869195
数 据 驱 动 未 来
Data Drives The Future