iOS: 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完成渐进加载图片的更多相关文章
- 【iOS入门】UITableView加载图片
学习带图片的列表 官方 LazyTableImages demo http://download.csdn.net/detail/jlyidianyuan/5726749 分析源码是学习的好方法. ...
- iOS两种方式加载图片的区别
加载图片的方式: imageNamed: imageWithContentsOfFile: 加载Assets.xcassets这里面的图片: 1> 打包后变成Assets.car 2> 拿 ...
- IOS中UITableView异步加载图片的实现
本文转载至 http://blog.csdn.net/enuola/article/details/8639404 最近做一个项目,需要用到UITableView异步加载图片的例子,看到网上有一个E ...
- iOS多线程自定义operation加载图片 不重复下载图片
摘要:1:ios通过抽象类NSOperation封装了gcd,让ios的多线程变得更为简单易用: 2:耗时的操作交给子线程来完成,主线程负责ui的处理,提示用户的体验 2:自定义operati ...
- iOS 加载图片选择imageNamed 方法还是 imageWithContentsOfFile?
Apple官方的文档为生成一个UIImage对象提供了两种方法: 1. imageNamed,其参数为图片的名字: 2. imageWithContentsOfFile,其参数也是图片文件的路径. ...
- iOS网络加载图片缓存策略之ASIDownloadCache缓存优化
iOS网络加载图片缓存策略之ASIDownloadCache缓存优化 在我们实际工程中,很多情况需要从网络上加载图片,然后将图片在imageview中显示出来,但每次都要从网络上请求,会严重影响用 ...
- IOS学习之路二十三(EGOImageLoading异步加载图片开源框架使用)
EGOImageLoading 是一个用的比较多的异步加载图片的第三方类库,简化开发过程,我们直接传入图片的url,这个类库就会自动帮我们异步加载和缓存工作:当从网上获取图片时,如果网速慢图片短时间内 ...
- 10、 iOS 加载图片选择imageNamed 方法还是 imageWithContentsOfFile
Apple官方的文档为生成一个UIImage对象提供了两种方法: 1. imageNamed,其参数为图片的名字: 2. imageWithContentsOfFile,其参数是图片文件的路径. 两种 ...
- iOS网络加载图片缓存与SDWebImage
加载网络图片可以说是网络应用中必备的.如果单纯的去下载图片,而不去做多线程.缓存等技术去优化,加载图片时的效果与用户体验就会很差. 一.自己实现加载图片的方法 tips: *iOS中所有网络访问都是异 ...
随机推荐
- PowerCMD——cmd的命令行工具
之前就想整理一下程序员经常使用的一些工具,最近有时间正好整理一下. 有句话叫做:“工欲善其事必先利其器”,而我就算是搜集工具组装成一个系列——善事利器,来记录一下工作学习中常用的一些工具. 总结起来, ...
- windows2003 单网卡 搭建vpn ,windows 2008 R2 类似吧。网上转的,自己加了点经验总结
先说说可能的坑,也就是我自己搭建的时候碰到的问题. 其实搭建起来很简单,我不知道我总结的对还是不对,但是按下面这样操作做绝对能搭好!因为我就是按这样搭起来的,但是我发现,好像pptp已经被墙了,我也不 ...
- 性能指标TP99之我解
首先给出Google到的答案: The tp90 is a minimum time under which 90% of requests have been served. tp90 = top ...
- 第四章 一切从IL开始
从这一部分开始,就开始讲.net的本质了,这第四章就是讲有关IL(中间语言)的内容,主要利用工具,看看VS到底编译出来的是什么东西,从中我们可以看到实现的方式和过程.有助于我们更好的了解.net的本质 ...
- 记录nginx 搭建集群环境踏过的坑
因为生产环境做了负载均衡,为了尽可能跟线上环境一致,所以想在本地也搭集群,这样测试更靠谱.首先就想到nginx 这货,搭个简单的web 服务器实在太简单了. nginx 这玩意11年简单玩过,那是版本 ...
- [poj3666]Making the Grade(DP/左偏树)
题目大意:给你一个序列a[1....n],让你求一个序列b[1....n],满足 bi =a && bc,则最小的调整可以是把b变成c. 所以归纳可知上面结论成立. dp[i][j] ...
- 年终福利:调试.NET Framework源代码
前言 要问JAVA语言最大的优势之一,那就是开源.开源的JAVA框架让JAVA程序员可以不断的通过看源代码来学习.成长.解决问题.并随着时间增长能力越来越强,自然薪水就越来越高.而DONET程序员要看 ...
- 小心as"陷阱"(c#)
有一种情况,使用as编译时没错,运行时也没错,但是结果错了. object a=1; string b=a as String; 由于a是objecy类型,是引用类型,所以可以用as转换,但是实际上b ...
- 软件工程(QLGY2015)第一次作业小结(含成绩)
相关博文目录: 第一次作业点评 第二次作业点评 第三次作业点评 Github项目提交 github的代码提交,大部分人都只是提交了单个文件,存在几个问题 请提交完整的项目文件到github 问题:为什 ...
- 图解Android - Android GUI 系统 (5) - Android的Event Input System
Android的用户输入处理 Android的用户输入系统获取用户按键(或模拟按键)输入,分发给特定的模块(Framework或应用程序)进行处理,它涉及到以下一些模块: Input Reader: ...