美文网首页
重读YYImage有感

重读YYImage有感

作者: 重案组之虎曹达华_ | 来源:发表于2020-09-29 11:30 被阅读0次

    前言

    这篇文章写在我毕业工作的第五个年头,从前一直觉得自己挺牛的,什么东西都一学就会。

    实至今日,才发现自己的能力在各方面是有多弱,和牛逼的人差距是有多大。计算机的很多基础知识都极为薄弱。

    青春期最最最后悔的事,就是没有好好读书,天天想着怎么逃课,泡妞。

    其实15年刚刚做iOS的时候就接触过YYImage,当时就是觉得挺屌的,大家都在吹,我也用呗。也没有好好读过源码。

    最近因为业务需要,对各种图片格式也有了新的认识,索性重新来读一遍YYImage,顺便总结一些感想

    YYImage是YYKit系列中的其中一个组件,大神自己口述是在大概搞iOS的第五个年头写出来的。

    我自认为我在第五个年头,才能静下心来把源码好好地从头到尾理顺,而人家已经在第五个年头发布了这个iOS中国最优秀之一的框架。

    其实自己跟别人比起来,真是没什么天赋,只有多花时间,少一些玩的时间。

    正文

    其实纵观整个YYImage还是基于ImageIO和CoreGraphics的相关api进行一系列操作的。

    • 加载一张普通静态图的大致步骤:
      1. 通过分辨率和图片格式加载图片进内存
      2. 通过源数据判断判断图片类型
      3. 通过图片类型进行源数据的信息获取,这里作者大概分为三类,webp:依赖于libwebp ,png和apng作者自己写了一套数据解析的算法(这里我暂时放弃了..下次一定学),剩下的都基于ImageIO,通过_YYImageDecoderFrame私有属性保存源数据信息。
      4. 调用ImageIO相关api进行解码,之后就可以愉快地使用了。
    • 加载一张动图的大致步骤:
      1. 和加载静态的图流程差不多,源数据会多记录一些东西,比如每一帧的druation,每一帧的渲染方式。详见这篇,原作者讲的很详细(在解码动图时,解码器通常采用所谓“画布模式”进行渲染。想象一下:播放的区域是一张画布,第一帧播放前先把画布清空,然后完整的绘制上第一帧图;播放第二帧时,不再清空画布,而是只把和第一帧不同的区域覆盖到画布上,就像油画的创作那样。像这样的第一帧就被称为关键帧(即 I 帧,帧内编码帧),而后续的那些通过补偿计算得到的帧被称为预测编码帧(P帧)。一个压缩的比较好的动图内,通常只有少量的关键帧,而其余都是预测编码帧;一个较差的压缩工具制作的动图内,则基本都是关键帧。不同的动图压缩工具通常能得到不同的结果。)这些其实都很详细地记录在图片的原数据里。
      2. 显示动图必须用YYAnimatedImageView承接,用UIImageView只会显示第一帧(这是YYImage内部实现的原因),每个YYAnimatedImageView里都有一个CADisplayLink,通过屏幕绘制频率进行进度计算和异步解码。实现边播放边解码的高性能操作。

    疑点总结

    1. 对于动图来说,假设其中一帧进度时间小于0.011秒,强制将这一帧时间提升到0.1秒。至于原因其实源码当中是有备注的。

      大致原因在于:许多恼人的广告指定0秒持续时间,以到达最快速度的闪烁,我们遵循Safari和Firefox的行为,对于指定持续时间<=10毫秒的任何帧,使用100毫秒的持续时间

      这也是ImageIO源码中的原话

      // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
      // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
      // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
      // for more information.
      

      至于为什么是100毫秒,下面其实也有说到,

      没有一个现代浏览器支持0.02秒以下的帧延迟。因此,当创建动画GIF时,绝不应使用低于此阈值的帧延迟,因为这将完全无效。另一个有趣的发现是Safari是唯一一个在GIF动画播放方面性能下降的浏览器。

      对于那些对创建和观看流畅、快速的动画感兴趣的人来说,Chrome、Firefox和Opera无疑是不错的选择。这些浏览器都支持0.02秒的最小帧延迟,从而使动画GIF以每秒50帧的速度运行。然而,这种能力需要与交叉兼容性问题进行权衡。

      由于Safari和internetexplorer决定只支持0.06秒的帧延迟(低于此值的四舍五入为0.10秒),动画的观看速度有可能大大低于预期。所讨论的GIF将以每秒10帧的速度播放,而不是期望的每秒50帧。只有20%的真实速度,这成为一个认真考虑美学影响。(翻译而来差不多看看)

    2. 对于单张静态图片的加载,YYImage和UImage的加载方式略有不同,同样是imageNamed:(NSString *)name方法,UImage不会解码,而是在UIImageView addView的时候才进行解码,而YYImage会在调用该方法后当场解码,因此放入异步线程进行解码还可以减少主线程压力。

    3. 几种常见的图片保存格式

      第一种是 baseline,即逐行扫描。默认情况下,JPEG、PNG、GIF 都是这种保存方式。
      第二种是 interlaced,即隔行扫描。PNG 和 GIF 在保存时可以选择这种格式。
      第三种是 progressive,即渐进式。JPEG 在保存时可以选择这种方式。
      调用CGImageSourceUpdateData(data, false) 可以实现类似于网页中的渐进式显示的效果。

    4. preloadAllAnimatedImageFrames该属性可支持提前解开所有帧图片,使在动图播放过程中减少cpu的开销,但是可能会造成oom,所以视情况而定进行使用。

    5. 强如webp也有他的性能瓶颈,那就是解码效率,没有方案是万能的,bitmap,png,wep各自都有他们的存在场景,假如以后计算机的存储量和网络流量都无限大,随便用,那么我完全可以使用bitmap,我为什么要使用webp去消耗额外的cpu或者gpu的开销呢。

    6. 其实YYImage当中还有很强大的encode功能,支持多种格式和参数(quality质量,lossless无损等),不过我个人在实际业务中用到的比较少。

    遗留问题

    读源码的过程中还是碰到某几处地方还是没有特别的理解,希望后续有机会能得到答案

    1. 关于在解码类的入口函数递归锁的使用

      - (BOOL)updateData:(NSData *)data final:(BOOL)final {
          BOOL result = NO;
          pthread_mutex_lock(&_lock);
          result = [self _updateData:data final:final];
          pthread_mutex_unlock(&_lock);
          return result;
      }
      

      我认为对于递归锁的本质来说,其实就是给递归方法用的。使得同一线程在同一区块可以进行重入,但是对于该方法,我来来回回看了很多遍都没发现怎么会出现重入的情况,所以对于这里还是挺疑惑的,这里用递归锁的意义。

    2. 关于缓冲区的下一帧的移除操作

      在CADisplayLink每次触发的step方法中有这么一段

      bufferedImage = buffer[@(nextIndex)];
      if (bufferedImage) {
       if ((int)_incrBufferCount < _totalFrameCount) {
           [buffer removeObjectForKey:@(nextIndex)];
       }
      ....
      } else {
           _bufferMiss = YES;
      }
      

      经过多次的调试,没太明白[buffer removeObjectForKey:@(nextIndex)]这句话的意义,因为由于子线程的解码速度一定是大于当前播放的帧数的,所以其实每次每次来到这个地方,nextIndex基本是解完了的,但这里先是在buffer中移除下一帧图片,但后续又在Operationmain重新拿到(虽然有缓存)进行添加的,因为buffer最终还是会保存所有的帧图片。而且我移除这句话也没发现啥问题,所以没有很搞懂移除的操作是为了啥

    3. 待学部分:png的图片格式数据解析,包括图片的解码算法。

    感谢

    移动端图片格式调研

    iOS 处理图片的一些小 Tip

    相关文章

      网友评论

          本文标题:重读YYImage有感

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