博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS图像解码
阅读量:2348 次
发布时间:2019-05-10

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

 

1、CGContextDrawImage方式(CoreGraphics)

    它接受一个原始的位图参数 imageRef ,最终返回一个新的解压缩后的位图 newImage ,中间主要经过了以下三个步骤:

使用 CGBitmapContextCreate 函数创建一个位图上下文;

使用 CGContextDrawImage 函数将原始位图绘制到上下文中;

使用 CGBitmapContextCreateImage 函数创建一张新的解压缩后的位图。

 

2、CGImageGetDataProvider方式(ImageIO)

1.CGImageSourceCreateWithData(data) 创建ImageSource。

2.CGImageSourceCreateImageAtIndex(source) 创建一个未解码的 CGImage。

3.CGImageGetDataProvider(image) 获取这个图片的数据源。

4.CGDataProviderCopyData(provider) 从数据源获取直接解码的数据。

ImageIO 解码发生在最后一步,这样获得的数据是没有经过颜色类型转换的原生数据(比如灰度图像)。

  1.NSString *resource = [[NSBundlemainBundle] pathForResource:@"the_red_batman"ofType:@"png"];

    2. NSData *data = [NSData  dataWithContentsOfFile:resource options:0error:nil];

    3. CFDataRef  dataRef = (__bridge CFDataRef)data;

    4. CGImageSourceRef source =CGImageSourceCreateWithData(dataRef, nil);

    5. CGImageRef cgImage =CGImageSourceCreateImageAtIndex(source, 0, nil);

    6. CFDataRef rawData =CGDataProviderCopyData(CGImageGetDataProvider(cgImage));

    7.UIImage *image = [UIImageimageWithCGImage:cgImage];

 

图片的空间消耗

1磁盘空间或者通过internet传输所消耗的空间

2解压缩空间,通常是长X宽X高X4字节(RGBA)

3当显示在一个view中时,view本身也需要空间来存储layer

对于这里的第一个问题,有一个可能的优化方法:将压缩的文件拷贝到内存中不如映射到内存中,NSData有能力来假设一块磁盘空间是在内存中的,这样当访问这个图片时实际上就是从磁盘访问而不是从内存。据说CGImage知道哪种访问方式是最高效的,UIImage只是将CGImage封装了一下。

图片加载时间

对于“将这些像素显示到屏幕上最快要多久?”这个问题,显示一个图片所消耗的时间由以下三个因素决定:

1从磁盘上alloc/initUIImage的时间

2解压缩的时间

3 将解压缩后的比特转换成CGContext的时间,通常需要改变尺寸,混合,抗锯齿工作。

 

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

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

2.怎么能避免缓存呢?

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

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

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

1.CGImageSourceCreateWithData(data) 创建ImageSource。

2.CGImageSourceCreateImageAtIndex(source) 创建一个未解码的 CGImage。

3.CGImageGetDataProvider(image) 获取这个图片的数据源。

4.CGDataProviderCopyData(provider)从数据源获取直接解码的数据。

4. 如何判断一个文件的图片类型?

通过读取文件或数据的头几个字节然后和对应图片格式标准进行比对。我在写了一个简单的函数,能很快速的判断图片格式。

 

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

 demo: 

 

 

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

  

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

第二种是 interlaced,即隔行扫描。PNG 和 GIF 在保存时可以选择这种格式。

第三种是 progressive,即渐进式。JPEG 在保存时可以选择这种方式。

在下载图片时,首先用CGImageSourceCreateIncremental(NULL) 创建一个空的图片源,随后在获得新数据时调用

CGImageSourceUpdateData(data,false) 来更新图片源,

最后在用CGImageSourceCreateImageAtIndex() 创建图片来显示。

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

6.如何把 GIF 动图保存到相册?

iOS 的相册是支持保存 GIF 和 APNG 动图的,只是不能直接播放。用 [ALAssetsLibrarywriteImageDataToSavedPhotosAlbum:metadata:completionBlock] 可以直接把 APNG、GIF 的数据写入相册。如果图省事直接用 UIImageWriteToSavedPhotosAlbum() 写相册,那么图像会被强制转码为 PNG。

7.强制解压缩

    当第一次使用图片时,iOS会解压它。通常这个解压缩后的版本将滞留一段时间(内存允许)。尽管这么做没什么意义,但你可以通过将图片渲染成一个新的图片来解压缩这个图片。这样你将在一小段时间内获得两个解压缩的版本。

- (void)decompressImage:(UIImage *)image

{

   UIGraphicsBeginImageContext(CGSizeMake(1, 1));

    [imagedrawAtPoint:CGPointZero];

    UIGraphicsEndImageContext();

}

这一段代码会解压缩这个image,即时它只有一个像素。

     奇怪的是如果UIImage只是通过initWithContentsOfFile创建的,我不能始终保持这个解压缩的版本。所以我必须使用ImageIO framework(iOS 4之后可用) 中提供的一个选项来显式保持这个解压缩的版本:

   NSDictionary *dict = [NSDictionarydictionaryWithObject: [NSNumber numberWithBool:YES]                                                     

                                                              forKey:(id)kCGImageSourceShouldCache];

   CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url,NULL);

    CGImageRef cgImage =CGImageSourceCreateImageAtIndex(source, 0, (CFDictionaryRef)dict);

   UIImage *retImage = [UIImage imageWithCGImage:cgImage];

   CGImageRelease(cgImage);

   CFRelease(source);

 

    这样初始化图片就可以让解压缩仅发生一次:第一次解压缩消耗很长一段时间,第二次完全不消耗。这其中的关键就是kCGImageSourceShouldCache,你可以为CGImageSource和CGImageSourceCreateImageAtIndex使用这个选项,头文件中是这样说明的:

     Specifies whether the image should becached in a decoded form. The value of this key must be a CFBooleanRef; thedefault value is kCFBooleanFalse.

如果这个选项设置为NO,绘制图片的时间又会随着解压缩时间增长,如果设置为YES就仅仅解压缩一次。

 

   

l   iOS中的imageIO与image解码

http://ios.jobbole.com/87233/

l   谈谈 iOS 中图片的解压缩

http://blog.leichunfeng.com/blog/2017/02/20/talking-about-the-decompression-of-the-image-in-ios/

l   iOS/OSX 下对各类图片的编解码、图片裸数据(bitmapdata)的获取、根据裸数据(bitmap)重构图片,及源码

http://blog.csdn.net/hbw1992322/article/details/51957285

l   imageIO完成渐进加载图片

l   [

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

l   图片处理:Image I/O学习笔记

l   Image I/O 编程指引http://blog.csdn.net/king2716/article/details/

l   Image I/O编程指南

你可能感兴趣的文章
VNC server简单配置vnc
查看>>
win7 安装的offic2007
查看>>
rman本库恢复性测试
查看>>
IBM TSM磁带管理操作小记一则
查看>>
ORA-00258: NOARCHIVELOG 模式下的人工存档必须标识日志
查看>>
Java调用bat文件
查看>>
此责任无可用函数
查看>>
java获取数字和汉字
查看>>
excel Option Explicit webadi
查看>>
ICX错误
查看>>
windows Xp NTLDR is missing
查看>>
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
查看>>
Centos 6.x 安装配置MySQL
查看>>
-source 1.5 中不支持 diamond 运算 请使用 -source 7 或更高版本以启用
查看>>
jar包读取资源文件报错:找不到资源文件(No such file or directory)
查看>>
超简单:Linux安装rar/unrar工具与解压到目录示例
查看>>
Eclipse创建Maven Java8 Web项目,并直接部署Tomcat
查看>>
RedHad 7.x服务器操作记录
查看>>
BindException: Cannot assign requested address (Bind failed)解决办法
查看>>
Centos7:Docker安装Gitlab
查看>>