[iOS]系统升级后应用无法展示WebP格式图片问题
资源:
备份:SDWebImage、YYImage
比较惭愧,虽然问题解决了,但并未找到为什么系统升级会导致WebP解析失败的原因,希望知道的朋友分享一下。
情况介绍:
前段时间新供职公司所有线上APP出了一个问题,苹果手机升级11.2后应用中解析WebP格式图片全部失败。
这套APP核心功能是用户DIY家装场景,由于需要网络请求并快速展示大量图片,设计之初就决定使用现在比较流行的WebP格式来提高功能的流畅性。
实话说之前对
WebP不怎么了解,只知道是谷歌(google)开发的一种加快图片加载速度的图片格式,然而苹果并不支持,若一定需要使用
WebP则需要在本地通过代码或工具将之转换为jpg或png。
我的前任公司上个程序员是使用第三方SDWebImage来加载webp,如图一SDWebImage有个WebP.framework框架,在加载网络图片时已经支持
WebP格式。但是SDWebImage对
WebP格式支持得不完美,当然也可能是我们使用的版本有问题。据我向同事了解,以前系统升级时加载
WebP也曾出现过无法解析的问题,那么如今再次出现同样的问题就感觉有点危险。
查看UIImage+WebP.m中解析源码发现,iOS11.1这方法能正常解析Data为image,但iOS11.2这个方法就无法解析Data了。
+ (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)) {
NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary];
[errorDetail setValue:@"Header formatting error." forKey:NSLocalizedDescriptionKey];
if(error != NULL)
*error = [NSError errorWithDomain:[NSString stringWithFormat:@"%@.errorDomain", [[NSBundle mainBundle] bundleIdentifier]] code:-101 userInfo:errorDetail];
return nil;
}
WebPDecoderConfig config;
if(!WebPInitDecoderConfig(&config)) {
NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary];
[errorDetail setValue:@"Failed to initialize structure. Version mismatch." forKey:NSLocalizedDescriptionKey];
if(error != NULL)
*error = [NSError errorWithDomain:[NSString stringWithFormat:@"%@.errorDomain", [[NSBundle mainBundle] bundleIdentifier]] code:-101 userInfo:errorDetail];
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) {
NSString *errorString = [self statusForVP8Code:decodeStatus];
NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary];
[errorDetail setValue:errorString forKey:NSLocalizedDescriptionKey];
if(error != NULL)
*error = [NSError errorWithDomain:[NSString stringWithFormat:@"%@.errorDomain", [[NSBundle mainBundle] bundleIdentifier]] code:-101 userInfo:errorDetail];
return nil;
}
// Construct UIImage from the decoded RGBA value array
uint8_t *data = WebPDecodeRGBA([imgData bytes], [imgData length], &width, &height);
CGDataProviderRef provider = CGDataProviderCreateWithData(&config, data, config.options.scaled_width * config.options.scaled_height * 4, free_image_data);
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault |kCGImageAlphaLast;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
CGImageRef imageRef = CGImageCreate(width, height, 8, 32, 4 * width, colorSpaceRef, bitmapInfo, provider, NULL, YES, renderingIntent);
UIImage *result = [UIImage imageWithCGImage:imageRef];
// Free resources to avoid memory leaks
CGImageRelease(imageRef);
CGColorSpaceRelease(colorSpaceRef);
CGDataProviderRelease(provider);
WebPFreeDecBuffer(&config.output);
return result;
}
一开始确定是解析失败导致
WebP无法展示时,个人觉得实力不够搞定不了这个问题,感觉很无力。还好当时手上有更重要的项目在限期开发,这问题被压下暂时搁置了几天。经常开玩笑说,这问题要升级最新iOS系统才会发生,“手贱”点升级系统的人活该!
解决方案:
前两天重新思考解决这个问题时,发现很简单并没有想象中复杂。我们已经获取到了
WebP的data,要最小代价的修复问题,只需要重写上面那个解析方法将
WebP的data转换成UIImage并返回就行了,下面主要是按照这个思路。
百度
WebP如何转换成jpg时,发现有人推荐
YYImage支持WebP、APNG、GIF格式动画图像的播放/编码/解码。苹果不是不支持webp格式么,那么这个YYImage的demo中就一定也存在
WebP的data转换Image的方法,只要这个方法与SDWebImage中的方法不一样那么之前的问题就解决了。
如图二发现WebP.framework框架更丰富,查看YYImage.h有方法“+ (nullable YYImage *)imageWithData:(NSData *)data;”。那么导入项目重写方法WebP无法展示的问题就得到了解决。
+ (UIImage *)imageWithWebPData:(NSData *)imgData error:(NSError **)error
{
UIImage *webpImage = [YYImage imageWithData:imgData];
return webpImage;
}
[图一]
[图二]