imageIO完成渐进加载图片

  不得不说,人都是有惰性的,一个月又快结束了,这个月虽说有点儿忙,但是绝对不差写几篇博客的时间,有时间去n次桌球厅,有时间玩n把英雄联盟,所谓小撸怡情大撸伤身,这个月游戏打得有点儿多,后面还是的控制一点儿。不扯了,下面进入正题,今天写写这个月初时使用imageIO框架实现的一个从web拉取,渐进加载图片的图片。

  前面有一篇使用imageIO获取和修改图片的exif信息介绍了使用imageIO获取图片的exif信息,在看到Image I/O Programming Guide的时候注意到了,文档中提到了可以使用CGImageSource实现渐进加载的功能,于是想着自己写个程序试试。

一、常见渐进加载图片模式

  目前我们看到的渐进加载主要有以下三种实现方式:

  1)  依次从web上加载不同尺寸的图片,从小到大。最开始先拉取一个小缩略图做拉伸显示,然后拉取中等规格的图,拉取完毕直接覆盖显示,最后拉取原图,拉取完成后显示原图。

  2)直接从web上拉取最大的图片,每接受一点儿数据就显示一点儿图片,这样就会实现从上到下一点点刷新出来的效果。

  3)结合第1种和第2种,先拉取一个缩略图做拉伸显示,然后采用第二种方法直接拉取原图,这样即可以实现渐进加载,也可以节省几次中间的网络请求。

二、通过imageIO实现图片的渐进加载

  imageIO的guide中原话是这么说的: "If you have a very large image, or are loading image data over the web, you may want to create an incremental image source so that you can draw the image data as you accumulate it. "

  翻译过来就是: "如果你想加载一副特别大的图片,或者从网络上加载一副图片,你可以通过创建一个imageSource实现渐进加载的效果。"翻译的不是很地道,大概就是这么个意思,以前在做PowerCam的时候,当时为了在iOS上处理超大图的时候也试过这种方法,当时测试使用的是一副中国地图,分辨率为10000*8000的,结果是当整幅图片加载到内存时,内存吃不消,于是就放弃了。现在想想对于这种超大图片的处理,我们可以采用分片的方式进行,每次只需要处理一小块图片即可,这个问题就留给大家思考吧。

  今天我们要讨论的是CGImageSource实现从web端渐进加载图片,要达到这个目的我们需要创建一个URLConnnection,然后实现代理,每次接收到数据时更新图片即可。下面主要的实现源码:

//
// SvIncrementallyImage.m
// SvIncrementallyImage
//
// Created by maple on 6/27/13.
// Copyright (c) 2013 maple. All rights reserved.
// #import "SvIncrementallyImage.h"
#import <ImageIO/ImageIO.h>
#import <CoreFoundation/CoreFoundation.h> @interface SvIncrementallyImage () {
NSURLRequest *_request;
NSURLConnection *_conn; CGImageSourceRef _incrementallyImgSource; NSMutableData *_recieveData;
long long _expectedLeght;
bool _isLoadFinished;
} @property (nonatomic, retain) UIImage *image;
@property (nonatomic, retain) UIImage *thumbImage; @end @implementation SvIncrementallyImage @synthesize imageURL = _imageURL;
@synthesize image = _image;
@synthesize thumbImage = _thumbImage; - (id)initWithURL:(NSURL *)imageURL
{
self = [super init];
if (self) {
_imageURL = [imageURL retain]; _request = [[NSURLRequest alloc] initWithURL:_imageURL];
_conn = [[NSURLConnection alloc] initWithRequest:_request delegate:self]; _incrementallyImgSource = CGImageSourceCreateIncremental(NULL); _recieveData = [[NSMutableData alloc] init];
_isLoadFinished = false;
} return self;
} #pragma mark -
#pragma mark NSURLConnectionDataDelegate - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
_expectedLeght = response.expectedContentLength;
NSLog(@"expected Length: %lld", _expectedLeght); NSString *mimeType = response.MIMEType;
NSLog(@"MIME TYPE %@", mimeType); NSArray *arr = [mimeType componentsSeparatedByString:@"/"];
if (arr.count < || ![[arr objectAtIndex:] isEqual:@"image"]) {
NSLog(@"not a image url");
[connection cancel];
[_conn release]; _conn = nil;
}
} - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"Connection %@ error, error info: %@", connection, error);
} - (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"Connection Loading Finished!!!"); // if download image data not complete, create final image
if (!_isLoadFinished) {
CGImageSourceUpdateData(_incrementallyImgSource, (CFDataRef)_recieveData, _isLoadFinished);
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_incrementallyImgSource, , NULL);
self.image = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
}
} - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_recieveData appendData:data]; _isLoadFinished = false;
if (_expectedLeght == _recieveData.length) {
_isLoadFinished = true;
} CGImageSourceUpdateData(_incrementallyImgSource, (CFDataRef)_recieveData, _isLoadFinished);
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_incrementallyImgSource, , NULL);
self.image = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
} @end

  从上面代码中我们可以看到,一开始我们根据传入的URL创建一个URLConnection,同时创建一个空的CGImageSource,然后在每次收到数据的时候调用CGImageSourceUpdateData更新imageSource的数据,接着调用CGImageSourceCreateImageAtIndex获取最新的图片即可。

  怎么样,看到上面的实现是不是感觉实现从web上渐进加载图片很简单,虽然imageIO帮我们做了很多事情,但是我们也应该了解它的原理。我们知道文件都是有格式的,一般文件的头部会记录一些关于文件格式的数据,后面就是实际的文件数据。

  拿最简单的BMP图片文件举例:

  1)  最开始的BITMAPFILEHEADER,这部分主要记录文件的大小,以及实际的图像数据离文件头的距离。

  2)  接着是BITMAPINFOHEADER,这部分主要记录图片的宽,高,位深等信息

  3)可选的调色板信息

  4)最后一部分就是实际的图片数据。

  前三部分的信息很小,一般加起来不会超过100个字节,获取到这写信息以后,我们就可以很轻松的根据后面的数据构建出图片,当数据获取的越来越完整的时候,我们构造出的图片就会越完整,直至全部加载完成。

  BMP格式是简单的图片格式,其他的JPG,PNG虽然结果更加复杂,但是总体构成都差不多。imageIO正是帮助我们完成了众多图片格式的编解码,然后一步步构造出最终的图片。

三、总结

  本文主要讨论了渐进加载图片的原理,并且介绍了iOS平台使用imageIO实现从web端渐进加载图片的功能。

  完整的源码在我的github: https://github.com/smileEvday/SvIncrementallyImage

  感兴趣的,可以下载看看,代码中如果有什么不对的地方欢迎指正。

注:转载请著名出处,本人QQ: 1592232964,欢迎一起讨论iOS开发的知识!!!

iOS: imageIO完成渐进加载图片的更多相关文章

  1. 【iOS入门】UITableView加载图片

    学习带图片的列表 官方 LazyTableImages demo  http://download.csdn.net/detail/jlyidianyuan/5726749 分析源码是学习的好方法. ...

  2. iOS两种方式加载图片的区别

    加载图片的方式: imageNamed: imageWithContentsOfFile: 加载Assets.xcassets这里面的图片: 1> 打包后变成Assets.car 2> 拿 ...

  3. IOS中UITableView异步加载图片的实现

    本文转载至 http://blog.csdn.net/enuola/article/details/8639404  最近做一个项目,需要用到UITableView异步加载图片的例子,看到网上有一个E ...

  4. iOS多线程自定义operation加载图片 不重复下载图片

    摘要:1:ios通过抽象类NSOperation封装了gcd,让ios的多线程变得更为简单易用:   2:耗时的操作交给子线程来完成,主线程负责ui的处理,提示用户的体验   2:自定义operati ...

  5. iOS 加载图片选择imageNamed 方法还是 imageWithContentsOfFile?

      Apple官方的文档为生成一个UIImage对象提供了两种方法: 1. imageNamed,其参数为图片的名字: 2. imageWithContentsOfFile,其参数也是图片文件的路径. ...

  6. iOS网络加载图片缓存策略之ASIDownloadCache缓存优化

    iOS网络加载图片缓存策略之ASIDownloadCache缓存优化   在我们实际工程中,很多情况需要从网络上加载图片,然后将图片在imageview中显示出来,但每次都要从网络上请求,会严重影响用 ...

  7. IOS学习之路二十三(EGOImageLoading异步加载图片开源框架使用)

    EGOImageLoading 是一个用的比较多的异步加载图片的第三方类库,简化开发过程,我们直接传入图片的url,这个类库就会自动帮我们异步加载和缓存工作:当从网上获取图片时,如果网速慢图片短时间内 ...

  8. 10、 iOS 加载图片选择imageNamed 方法还是 imageWithContentsOfFile

    Apple官方的文档为生成一个UIImage对象提供了两种方法: 1. imageNamed,其参数为图片的名字: 2. imageWithContentsOfFile,其参数是图片文件的路径. 两种 ...

  9. iOS网络加载图片缓存与SDWebImage

    加载网络图片可以说是网络应用中必备的.如果单纯的去下载图片,而不去做多线程.缓存等技术去优化,加载图片时的效果与用户体验就会很差. 一.自己实现加载图片的方法 tips: *iOS中所有网络访问都是异 ...

随机推荐

  1. 【转载】UVa 11464 Even Parity 偶数矩阵

    题意:给你一个n*n的01矩阵,让你把这个矩阵中尽量少的0转换成1,使得矩阵每个位置的上下左右四个相邻的数加起来能被2整除,求最少的转换数 首先,n 的规模并不大,最大只有15.但是完全枚举整个矩阵显 ...

  2. Chrome扩展开发之三——Chrome扩展中的数据本地存储和下载

    目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制 ...

  3. [转]细说MySQL Explain和Optimizer Trace简介

    在开发过程中,对每个上线的SQL查询指纹(query figerprint)的质量都应有估算:而估算DB查询质量最直接的方法,就是分析其查询执行计划( Query Execution Plan ,即Q ...

  4. Git.Framework 框架随手记--ORM编辑删除

    前面一篇文章<Git.Framework 框架随手记--ORM新增操作>主要讲解了如何使用Git.Framework往数据库中添加数据.其操作过程相对简单,本章主要记录如何编辑数据和修改数 ...

  5. [USACO2006][poj3182]The Grove(巧妙的BFS)

    题目:http://poj.org/problem?id=3182 题意:一个棋盘中间有一个联通块,给你一个起点让你从起点开始绕联通块外围一圈并回到起点,求最小步数. 分析: 首先根据数据的范围比较小 ...

  6. iOS开发小技巧--UIScrollView内部子控件添加约束的注意点

    注意:用UIScrollView时布局子控件的时候,不要相对于UIScrollView来添加约束,这样做不是设置子控件的位置,反而是设置了UIScrollView的contentSize 子控件的尺寸 ...

  7. C# 全角符号转半角

    public static string SBCCaseToNumberic(string SBCCase) { char[] c = SBCCase.ToCharArray(); ; i < ...

  8. 【BZOJ-2818】Gcd 线性筛

    2818: Gcd Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3347  Solved: 1479[Submit][Status][Discuss ...

  9. 【深入】java 单例模式(转)

    [深入]java 单例模式 关于单例模式的文章,其实网上早就已经泛滥了.但一个小小的单例,里面却是有着许多的变化.网上的文章大多也是提到了其中的一个或几个点,很少有比较全面且脉络清晰的文章,于是,我便 ...

  10. appium-向右滑动定位

    上面5幅欢迎图,要向右滑动4次再点击[立即体验]才可以到首屏 #首页欢迎图滑动4次 for i in range(4): driver.swipe(1200, 200, 10, 200, 1500) ...