美文网首页
视觉-iOS中图片文件渲染到屏幕的过程

视觉-iOS中图片文件渲染到屏幕的过程

作者: Johnny_Z | 来源:发表于2020-07-21 01:27 被阅读0次

一、图片到屏幕view过程

1、数据处理过程


图片数据
  • 1)将原始图片数据(png/jpg等)加载到内存中
  • 2)CPU解压图片数据
  • 3)渲染图片数据渲染到屏幕上

2、硬件协同处理细节

硬件处理
  • 1)CPU:计算视图frame,图片解码,需要绘制纹理图片通过数据总线交给GPU
  • 2)GPU: 纹理混合,顶点变换与计算,像素点的填充计算,渲染到帧缓冲区
  • 3)时钟信号:垂直同步信号V-Sync / 水平同步信号H-Sync
  • 4)iOS设备双缓冲机制:显示系统通常会引入两个帧缓冲区,双缓冲机制

二、图片加载到渲染的工作流程

1、从文件加载图片数据 可以使用类方法+imageNamed: ,此时我们得到图片原始数据
2、将UIImage 赋值给UIImageView
3、CATransaction捕获到UIImageView图层树的变化
4、主线程runloop提交 CATransaction,开始进行解码和图像渲染,这里会涉及到

  • 如果图像数据为未解码的PNG/JPG,解码为位图数据
  • GPU处理数据需要字节对齐,Core Animation会拷贝一份数据,进行字节对齐
  • GPU处理位图数据,进行渲染

5、渲染

  • GPU获取获取图片的坐标
  • 将坐标交给顶点着色器(顶点计算)
  • 将图片光栅化(获取图片对应屏幕上的像素点)
  • 片元着色器计算(计算每个像素点的最终显示的颜色值)
  • 从帧缓存区中渲染到屏幕上

注意:
1、图片只有在确认需要显示时,CPU才对其进行解压;+imageName:or+imageNamed:inBundle:compatibleWithTraitCollection:加载的图片,系统会对其自动缓存,以便下次使用,但如果用+imageWithContentsOfFile:-initWithContentsOfFile:系统会每次都从disk加载,对应的都需要解压;imageWithData直接读取原始数据,如果非GPU能直接处理的数据(位图或矢量图)是需要解压的;
2、解码是一个比较消耗CPU的操作,且默认在主线程,当界面上一次性确定显示多张图片时表现得尤为突出,此时一般的做法可以将解码操作放到异步线程去完成,解码后再用来展示

三、探究YYImage

1、YYImage 类结构分析

  • 图像层:YYImage, YYFrameImage, YYSpriteSheetImage
  • 视图层:YYAnimatedImageView
  • 编/解码层:YYImageCoder

2、分析YYAnimatedImageView

  • 初始化
- (instancetype)init {
    self = [super init];
    _runloopMode = NSRunLoopCommonModes;
    _autoPlayAnimatedImage = YES;
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    _runloopMode = NSRunLoopCommonModes;
    _autoPlayAnimatedImage = YES;
    return self;
}

- (instancetype)initWithImage:(UIImage *)image {
    self = [super init];
    _runloopMode = NSRunLoopCommonModes;
    _autoPlayAnimatedImage = YES;
    self.frame = (CGRect) {CGPointZero, image.size };
    self.image = image;
    return self;
}

初始化中指定了runloopModeNSRunLoopCommonModes

  • 动画的link
  [_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:_runloopMode];

_runloopMode 指定到了 CADisplayLinklink中,不断地替换_curFrame用来跟新layer里面显示的图片frame,将link的指定成NSRunLoopCommonModes保证了在拖动滚动视图时动画还能继续。

  • 图片解压 _YYAnimatedImageViewFetchOperation
//创建_requestQueue 设置最大并发量1
_requestQueue = [[NSOperationQueue alloc] init];
_requestQueue.maxConcurrentOperationCount = 1;
//解码操作加入_requestQueue
_YYAnimatedImageViewFetchOperation *operation = [_YYAnimatedImageViewFetchOperation new];
operation.view = self;
operation.nextIndex = nextIndex;
operation.curImage = image;
[_requestQueue addOperation:operation];
@implementation _YYAnimatedImageViewFetchOperation
- (void)main {
    ...
    
    for (int i = 0; i < max; i++, idx++) {
        @autoreleasepool {
            ...
            if (miss) {
                 //解码图片,并且标记
                UIImage *img = [_curImage animatedImageFrameAtIndex:idx];
                img = img.yy_imageByDecoded;
                if ([self isCancelled]) break;
                LOCK_VIEW(view->_buffer[@(idx)] = img ? img : [NSNull null]);
                view = nil;
            }
        }
    }
}
@end

可以看到,_YYAnimatedImageViewFetchOperation解码image图片的操作是通过
NSOperationQueue_requestQueue来异步来处理的

  • 图片数据buffer缓存
NSMutableDictionary *_buffer; ///< frame buffer

这里cache了显示所需要解压好的图片buffer数据,以便重复使用; 当然这里还有缓存限制和memory告警时清理缓存的机制,我这里就不一一赘述了

参考链接:
https://developer.apple.com/documentation/uikit/uiimage
https://www.jianshu.com/p/72dd074728d8
https://developer.apple.com/documentation/uikit/uiimage

相关文章

网友评论

      本文标题:视觉-iOS中图片文件渲染到屏幕的过程

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