博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ImagIO图片decode
阅读量:2347 次
发布时间:2019-05-10

本文共 3340 字,大约阅读时间需要 11 分钟。

  1.   iOS从磁盘加载一张图片,使用UIImageVIew显示在屏幕上,需要经过以下步骤:

1.       从磁盘拷贝数据到内核缓冲区

2.       从内核缓冲区复制数据到用户空间

3.       生成UIImageView,把图像数据赋值给UIImageView

4.       如果图像数据为未解码的PNG/JPG,解码为位图数据

5.       CATransaction捕获到UIImageViewlayer树的变化

6.       主线程Runloop提交CATransaction,开始进行图像渲染

   6.1 如果数据没有字节对齐,CoreAnimation会再拷贝一份数据,进行字节对齐。

   6.2 GPU处理位图数据,进行渲染。

 

   UIImage加载之后并没有立即解码,而是在显示或其他需要的时候解码,我们需要进行一次绘制,强制系统进行解码

     当通过 UIImage 展示一张图时,在显示之前需要解压缩(除非源已经像素缓存了)。对于 JPG/PNG文件这会占用相当可观的时间并会造成卡顿。iOS6以前,通常是创建一个位图上下文,然后在其中画图来解决。()。

iOS7 开始,你可以使用kCGImageSourceShouldCacheImmediately:来强制图片在创建时立即解压缩:

+ (UIImage*)decompressedImageWithData:(NSData *)data

{

    CGImageSourceRef source =CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);

    CGImageRef cgImage =CGImageSourceCreateImageAtIndex(source, 0, (__bridgeCFDictionaryRef)@{(id)kCGImageSourceShouldCacheImmediately: @YES});

    // kCGImageSourceShouldCacheImmediately = YES, 就会立即解码。

    UIImage *image = [UIImageimageWithCGImage:cgImage];

    CGImageRelease(cgImage);

    CFRelease(source);

    return image;

}

     

   当我刚发现这一点时确实很兴奋,但事实并非如此。在我的测试中,发现当开启了即时缓存后性能有明显的降低。要么这个方法是在主线程中调用的(不太可能),感觉上性能更糟,因为它在方法copyImageBlockSetJPEG中锁住了,而同时在主线程中在显示非加密的图片所致。在我的程序中,我在主线程中加载小的预览图,在后台线程中加载大型图,使用了kCGImageSourceShouldCacheImmediately后小小的解压缩阻塞了主线程,同时在后台处理大量开销昂贵的操作。

还有更多关于图片解压缩相关的却不是iOS7 中的新东西,像kCGImageSourceShouldCache,它用来控制系统自动卸载解压缩的图片数据的能力。确保你将它设置为YES,否则所有的工作都将没有意义。有趣的是,苹果在64bit运行时的系统中将kCGImageSourceShouldCache的默认值从NO 改为了YES

 

我要是用 imageWithData 能不能避免缓存呢?

不能。通过数据创建 UIImage 时,UIImage底层是调用ImageIO CGImageSourceCreateWithData() 方法。该方法有个参数叫 ShouldCache,在64 位的设备上,这个参数是默认开启的。这个图片也是同样在第一次显示到屏幕时才会被解码,随后解码数据被缓存到CGImage 内部。与imageNamed 创建的图片不同,如果这个图片被释放掉,其内部的解码数据也会被立刻释放。

http://blog.corneliamu.com/archives/95

 

     iOS中,使用 imageNamed 或者imageWithContentsOfFile 时,系统会调用 mmap( ) 将图片文件映射到虚拟内存,并创建 CGImageRef 用于后续访问图片数据。

   1imageNamed: 会在图片第一次渲染到屏幕上的时候进行解码,并缓存解码后的图片数据。缓存数据存储在全局缓存中,不会随着UIImag的释放而释放。

   2imageWithContentsOfFile:  imageWithData: 同样会在图片第一次渲染到屏幕上的时候进行解码。底层会调用到 CGImageSourceCreateWithData() 方法,该方法可以指定是否要缓存解码后的数据,在64位机器上默认需要缓存(kCGImageSourceShouldCache)。与上面的方法不同,这种方式创建的缓存会随着UIImage的释放而被释放掉。

  3)UIImageView 的图层树(Layer Tree)发生变化,会生成一个Implicit Transaction,这个transaction会自动在主线程的下一个 Runloop 进行提交。(Explicit Transaction 由显式调用 begin() 和 commit() 方法触发生成。)

  4)下一个Main Runloop中,Core Animation会提交这个 Implicit Transaction。如果用户内存中的位图数据没有 字节对齐 ,出于渲染性能考虑,Core Animation会对数据进行拷贝,以进行字节对齐。之后,GPU会渲染对齐后的位图数据,展示在屏幕上。

 

怎么能避免缓存呢?

1. 手动调用 CGImageSourceCreateWithData() 来创建图片,并把 ShouldCache ShouldCacheImmediately 关掉。这么做会导致每次图片显示到屏幕时,解码方法都会被调用,造成很大的 CPU 占用。

2. 把图片用 CGContextDrawImage() 绘制到画布上,然后把画布的数据取出来当作图片。这也是常见的网络图片库的做法。

我能直接取到图片解码后的数据,而不是通过画布取到吗?

1.CGImageSourceCreateWithData(data) 创建 ImageSource

2.CGImageSourceCreateImageAtIndex(source) 创建一个未解码的 CGImage
3.CGImageGetDataProvider(image)
获取这个图片的数据源。
4.CGDataProviderCopyData(provider)
从数据源获取直接解码的数据。
ImageIO
解码发生在最后一步,这样获得的数据是没有经过颜色类型转换的原生数据(比如灰度图像)。

 

 

怎样像浏览器那样边下载边显示图片?

首先,图片本身有 3 种常见的编码方式:

  

第一种是 baseline,即逐行扫描。默认情况下,JPEG、PNG、GIF 都是这种保存方式。

第二种是 interlaced,即隔行扫描。PNG 和 GIF 在保存时可以选择这种格式。
第三种是 progressive,即渐进式。JPEG 在保存时可以选择这种方式。
在下载图片时,首先用CGImageSourceCreateIncremental(NULL) 创建一个空的图片源,随后在获得新数据时调用
CGImageSourceUpdateData(data, false) 来更新图片源,最后在用 CGImageSourceCreateImageAtIndex() 创建图片来显示。

你可以用  或者我写的  来实现这个效果。SDWebImage 并没有用 Incremental 方式解码,所以显示效果很差。

【腾讯优测干货分享】使用多张图片做帧动画的性能优化

 

iOS 保持界面流畅的技巧

 

如何打造易扩展的高性能图片组件

 

iOS中ImageIO框架详解与应用分析

 

ImageIO.frameWork 解析

 

iOS疯狂详解之imageIO完成渐进加载图片

 

 

 

你可能感兴趣的文章
代码质量及其优化(学习笔记)
查看>>
将代码托管到GitHub
查看>>
Java实现PDF的生成(使用IText)
查看>>
MySQL学习笔记
查看>>
数据库连接池
查看>>
MySQL性能优化经验
查看>>
MySQL学习参考
查看>>
Java工程结构管理(BuildPath/系统库/外部库)
查看>>
将代码托管到Coding
查看>>
JS-异步提交表单的几种方式
查看>>
作为一个Java初学者应该注意些什么呢?
查看>>
27岁转行自学Java,真的太晚了吗?
查看>>
自学Java最起码要学到什么程度才能就业?
查看>>
零基础学Java需要做哪些准备?需要注意些什么呢?
查看>>
有了这份阿里大牛手写630页Java高级面试手册,offer稳了【建议收藏】
查看>>
学习Java,需要学到什么程度,才能出去找工作?
查看>>
2021年Java发展怎么样?现在学了Java技术出来是否还能找到工作?
查看>>
Java程序员面试大厂的技术标准,你达到要求了吗?
查看>>
为什么Java程序员需求量这么大,还会有人找不到合适的工作?
查看>>
过来人对程序员学习Java的10条建议,第2点很重要!
查看>>