记录WebP图片第三方平台分享,图片不显示问题

猪小花1号2018-09-05 12:15

作者:刘鼎


先说结论

WebP解码为UIImage时,需要将解码后的UIImage在画布中重新绘制一下,否则会导致UIImagePNGRepresentation转换失败

问题发生

美学小仙女们发布的心得合辑越来越多越来越漂亮,我们想把这些美好的东西分享出来,于是运营小伙伴们努力地把它们分享到微博、微信、QQ。 然而分享虽好,却有些掉链子,图片经常出问题。 以前都是少个图片分享链接,链接不对,图片被删除,这次却是遇到难题了。

起因是运营反馈,合辑分享到微信时,缩略图不显示。但是同一篇合辑,使用开发版分享显示正常。 再使用开发板测试相同类型其他内容分享、其他类型内容分享、H5分享,功能均正常。初步确认是发布版本问题,于是切换到老版本代码开始断点检查。

开始DEBUG

根据经验,平台最终分享前出问题可能性最大,自信满满地断了个点,结果缩略图果然为nil。

 

难道又是分享图是空的?继续debug,直到

 

什么鬼?!UIImagePNGRepresentation会失败?等等,上次长图分享好像也出现过,是WebP格式图片格式问题,把长图改为jpg格式分享就OK了,这次影响范围有点大,总不能把全部图片都改成jpg吧???看来这次得好好查查。既然测试版本没错,那我直接比较两个版本的代码修改记录就好了。线上版本是在9月29号上线的,看看之后改了啥修复了这个问题?于是

 




从分享图片到最初的SDWebImage方法调用,一!行!代!码!都!没!改!

第三方库?

难道更新过SDWebImage?是第三方库的问题,后来修复了?可能性太小了吧?然而没有其他可能了。

 

没!更!新!大写的绝望有木有。(其实问题出在这里,后面注释了subspecs。但测试版上也是注释的,而且分享正常,所以一开始排除了注释问题)
没办法,只能检查SDWebImage的源码了,既然是WebP问题,那查下SD中WebP相关代码吧

 

咦?SD_WEBP宏怎么没定义?难道就是这个原因?不对,那所有WebP图片应该都显示不出来,白高兴一场。 那图片是怎么解码的? 询问同事,原来还有个WebPImageSerialization类swizzle了UIImage的初始化方法

 

那看看它的WebP图片解码有没有问题吧。

image对象也有啊,虽然预览不出来,但打印信息正常,而且界面上图片显示也是正常的。 至此,似乎所有线索都断了。

转机

真相只有一个!排除所有不可能,剩下唯一一个疑点就是image预览失败问题,因为开发版中是可以预览的。那会不会是上图创建image时的某些参数问题呢? 而且UIImagePNGRepresentation上也写着

// May return nil if image has no CGImageRef or invalid bitmap format

于是Google关键字CGDataProviderRefCGColorSpaceRefCGBitmapInfo。。。
apple文档上的Pixel formats supported for bitmap graphics contexts中没有kCGImageAlphaLast!

WebPImageSerialization这个库生成的图片是有问题的,那开发版为什么是正常的?继续询问同事,原来线上版注释了SDWebImage的subspec Podfile,而开发版Podfile源使用时换成了framework,而framework在生成时是包含WebP的。还记得上面的Podfile截图么?

将注释去掉,重新运行,问题修复!大吉大利,今晚吃鸡~吃饭去鸟 

等等

BUG大魔王真的就这么被打败了?吃饭回来心血来潮:既然是BitmapInfo的问题,那我将kCGImageAlphaLast修改为kCGImageAlphaPremultipliedLast不就修复问题了?想到就干
晴天霹雳!

先确认下CGBitmapInfo选项的作用

typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {
    kCGImageAlphaNone,               /* For example, RGB. */
    kCGImageAlphaPremultipliedLast,  /* For example, premultiplied RGBA */
    kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */
    kCGImageAlphaLast,               /* For example, non-premultiplied RGBA */
    kCGImageAlphaFirst,              /* For example, non-premultiplied ARGB */
    kCGImageAlphaNoneSkipLast,       /* For example, RBGX. */
    kCGImageAlphaNoneSkipFirst,      /* For example, XRGB. */
    kCGImageAlphaOnly                /* No color data, alpha data only */
};

kCGImageAlphaLastkCGImageAlphaPremultipliedLast的区别仅在于是否预先在RGB空间中乘上alpha值。 但UIImage+WebP的确能解决问题,那看看SD的解决方案吧

sd_rawWebpImageWithData:中就是WebP格式的解析,但它将返回的staticImage又重新在画布中重新渲染了一遍。 依样画葫芦,经过CoreGraphics重绘的图片,问题终于彻底解决。 。

再等等

为什么重绘后就能解决问题?重绘前和重绘后的UIImage有什么区别?

打印CGImage,发现输出的颜色空间和位图格式有多项参数不一致。如果按CoreGraphics的配置输出,是不是就能省略重绘这一步? 这就是另外一个问题了,哪位同事有兴趣可以再试试,太一波三折了,容我先去吐血三升。。。

总结

  • debug遇到疑难杂症,能让人生多一些乐趣(然而我还是不想再遇到这种问题。。。)
  • 如果其他都绝对不可能,那看似不可能的,就变成了可能。
  • 多问一个为什么
  • 第三方库不是神圣不可侵犯的,多看看源码总不会错。
  • 常年不更新的第三库有踩坑风险(WebPImageSerialization最后一次更新于3年前)
  • 图片渲染不仅仅是JPEG\PNG\WebP解码为位图,位图也是有渲染格式的!

参考资料

Supported Pixel Formats
iOS kCGImageAlphaPremultipliedLast与kCGImageAlphaLast区别和联系
SDWebImage
兔斯基表情楼

网易云大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者刘鼎授权发布