显示图像数据的高级接口 UIImage

详解 UIKit:显示图像数据的高级接口 UIImage

转载自:http://www.cocoachina.com/ios/20151207/14376.html

分类:iOS开发 来源:南峰子的技术博客

本系列主要基于Apple官方文档,更多的是对参考文档重点内容的翻译与补充。该系列中的每篇文章会持续更新与补充。如有问题,欢迎通过微博告诉我,我将及时进行更正,谢谢!!!

UIImage对象是iOS中用来显示图像数据的高级接口。我们可以从文件,NSData,Quartz图片对象中创建UIImage对象。可以说这个类是我们接触频率非常高的一个类。

UIImage的不可变性

UIImage对象是不可变的,所以一旦创建后,我们就不能再改变它的属性。这也就意味着,我们只能在初始化方法中提供属性值或依赖于图片自身的属性值。同样,由于其不可变,所以在任何线程中都可以安全地使用它。

如果我们想修改UIImage对象的一些属性,则可以使用便捷方法和自定义的参数值来创建图像的一份拷贝。

另外,由于UIImage对象是不可变的,所以它没有提供访问底层图片数据的方法。不过我们可以使用UIImagePNGRepresentation或UIImageJPEGRepresentation方法来获取包含PNG或JPG格式的数据的NSData对象。如下代码所示:


1

2

let image = UIImage(named: "swift");

let imageData:NSData? = UIImageJPEGRepresentation(image!, 1.0)

创建UIImage对象

对于一个UIImage对象来说,它的数据源主要有以下几种:

  1. 文件:我们可以使用init(contentsOfFile:)方法来从指定文件中创建对象。
  2. 纯图片数据(NSData):如果在内存中有图片的原始数据(表示为NSData对象),则可以使用init(data:)来创建。需要注意的是这个方法会对象图片数据做缓存。
  3. CGImage对象:如果我们有一个CGImage对象,则可以使用init(CGImage:)或init(CGImage:scale:orientation:)创建UIImage对象。
  4. CIImage对象:如果我们有一个CIImage对象,则可以使用init(CIImage:)或init(CIImage:scale:orientation:)创建UIImage对象。

需要注意的是,如果是从文件或者纯图片数据中创建UIImage对象,则要求对应的图片格式是系统支持的图片类型。

对于Objective-C来说,UIImage对象也提供了这些初始化方法对应的便捷类方法来创建对象。

内存管理

在实际的应用中,特别是图片类应用中,我们可能需要使用大量的图片。我们都知道,图片通常都是非常占内存的。如果同一时间加载大量的图片,就可能占用大量的系统内存。

为此,Apple采用了一种比较巧妙的策略。在低内存的情况下,系统会强制清除UIImage对象所指向的图片数据,以释放部分内存。注意,这种清除行为影响到的只是图片数据,而不会影响到UIImage对象本身。当我们需要绘制那些图片数据已经被清除的UIImage对象时,对象会自动从源文件中重新加载数据。当然,这是以时间换空间的一种策略,会导致一定的性能损耗。

说到这里,我们不得不提一下init(named:)方法了。可以说我们平时创建UIImage对象用得最多的应该就是这个方法。这个方法主要是使用bundle中的文件创建图片的快捷方式。关于这个方法,有几点需要注意:

  1. 缓存:这个方法会首先去系统缓存中查找是否有图片名对应的图片。如果有就返回缓存中的图片;如果没有,则该方法从磁盘或者asset catalog中加载图片并返回,同时将图片缓存到系统中。缓存的图片只有在收到内存警告时才会释放。因此,如果图片的使用频率比较低,则可以考虑使用imageWithContentsOfFile:方法来加载图片,这样可以减少内存资源的消耗。当然,这需要权衡考虑,毕竟读写磁盘也是有性能消耗的,而且现在的高端机内存已经不小了。
  2. 多分辨率图片处理:在iOS 4.0后,该方法会根据屏幕的分辨率来查找对应尺寸的图片。即我们使用时,只需要写图片名,而不需要指定是1x, 2x还是3x图,该方法会自己判断。
  3. png图片后缀:在iOS 4.0以后,如果图片是png格式的,则图片文件名不需要附带扩展名。
  4. 线程安全性:该方法在iOS 9.0之前并不是线程安全的,在二级线程中调用可能会导致崩溃。在iOS 9.0之后,Apple作了优化处理,将其改为线程安全的方法。为了避免不必要的麻烦,尽量在主线程中调用这个方法。

图片拉伸

当我们的图片比所要填充的区域小时,会导致图片变形。如以下图片,原始大小为100*30,将其放到一个300*50的UIImageView中时,整个图片被拉伸。

原始图片

拉伸后的图片

这时我们就需要做特殊的处理。

Android的同学应该都知道.9图,这种图片可以只拉伸中间的部分,而保持四个角不变形。在iOS中也支持这种操作。在早期的iOS版本中,UIImage提供了如下方法来执行此操作:


1

func stretchableImageWithLeftCapWidth(_ leftCapWidth: Int, topCapHeight topCapHeight: Int) -> UIImage

这个方法通过leftCapWidth和topCapHeight两个参数来定义四个角的大小。不过这个方法在iOS 5中就被Deprecated了,对应的两个属性leftCapWidth和topCapHeight也是相同的命运。所以现在不建议使用它们。另外,对于如何解释leftCapWidth和topCapHeight,大家可以参考一下@M了个JiOS图片拉伸技巧

在iOS 5中,我们可以使用以下方法来执行相同的操作:


1

func resizableImageWithCapInsets(_ capInsets: UIEdgeInsets) -> UIImage

这个方法通过一个UIEdgeInsets来指定上下左右不变形的宽度或高度。它会返回一个新的图像。而如果图像被拉伸,则会以平铺的方式来处理中间的拉伸区域。

我们对上面的图片做如下处理:


1

2

let resizedButtonImageView = UIImageView(image: normalButtonImage?.resizableImageWithCapInsets(UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)))

resizedButtonImageView.frame = CGRectMake(0, 60, 300, 50)

其得到的结果如下所示:

在iOS 6,Apple又为我们提供了一个新的方法,相较于上面这个方法,只是多一个resizingMode参数,允许我们指定拉伸模式。


1

func resizableImageWithCapInsets(_ capInsets: UIEdgeInsets, resizingMode resizingMode: UIImageResizingMode) -> UIImage

这个方法的拉伸模式分两种:平铺(Tile)和拉伸(Stretch)。如果是平铺模式,则跟前一个方法是一样的效果。

动效图片对象

如果我们有一组大小和缩放因子相同的图片,就可以将这些图片加载到同一个UIImage对象中,形成一个动态的UIImage对象。为此,UIImage提供了以下方法:


1

class func animatedImageNamed(_ name: String, duration duration: NSTimeInterval) -> UIImage?

这个方法会加载以name为基准文件名的一系列文件。如,假设我们的name参数值为”swift”,则这个方法会加载诸如”swift0”, “swift1”,…, “swift1024”这样的一系列的文件。

这里有两个问题需要注意:

  1. 文件的序号必须是从0开始的连续数字,如果不从0开始,则在Playground中是会报错的。而如果中间序号有断,而中断后的图片是不会被加载的。
  2. 所有文件的大小和缩放因子应该是相同的,否则显示时会有不可预期的结果,这种结果主要表现为播放的顺序可能是杂乱的。

如果我们有一组基准文件名不同的文件,但其大小和缩放因子相同,则可能使用以下方法:


1

class func animatedImageWithImages(_ images: [UIImage], duration duration: NSTimeInterval) -> UIImage?

传入一个UIImage数组来拼装一个动效UIImage对象。

另外,UIImage也提供了resizable版本的动效方法,如下所示:


1

2

class func animatedResizableImageNamed(_ name: String, capInsets capInsets: UIEdgeInsets, duration duration: NSTimeInterval) -> UIImage?

class func animatedResizableImageNamed(_ name: String, capInsets capInsets: UIEdgeInsets, resizingMode resizingMode: UIImageResizingMode, duration duration: NSTimeInterval) -> UIImage?

第一个方法的UIImageResizingMode默认是UIImageResizingModeTile,所以如果想对图片做拉伸处理,可以使用第二个的方法,并传入UIImageResizingModeStretch。

图片大小的限制

UIImage对象使用的图片大小尽量小于1024*1024。因为这么大的图片消耗的内存过大,在将其作为OpenGL中的贴图或者是绘制到view/layer中时,可以会出现问题。如果仅仅是代码层面的操作的话,则没有这个限制。比如,将一个大于1024*1024的图片绘制到位图图形上下文中以重新设定其大小。事实上,我们需要通过这种操作来改变图片大小,以将其绘制到视图中。

支持的图片格式

UIImage支持的图片格式在UIImage Class Reference中列出来了,大家可以直接参考。

需要注意的一点是RGB-565格式的BMP文件在加载时会被转换成ARGB-1555格式。

示例代码

本文的示例代码已上传到github,可点击这里查看。

参考

时间: 2024-08-05 10:56:23

显示图像数据的高级接口 UIImage的相关文章

[c#]asp.net开发微信公众平台(8)微信9大高级接口,自定义菜单

前7篇把最基础的消息接收和回复全做完了,  也把高级接口的入口和分拆处理写好了空方法,  此篇接着介绍微信的9大高级接口, 并着重讲解其中的自定义菜单. 微信9大接口为: 1.语音识别接口 2.客服接口 3.OAuth2.0 网页授权接口 4.生成带参数的二维码接口 5.获取用户地理位置接口 6.获取用户基本信息接口 7.获取关注者列表接口 8.用户分组接口 9.上传下载多媒体文件接口 具体介绍: 1. 语音识别 功能描述:通过语音识别接口,用户发送的语音,将同时给出语音识别出的文本内容. 实用

【课程分享】深入浅出微信公众平台实战开发(微网站、LBS云、Api接口调用、服务号高级接口)

深入浅出微信公众平台实战开发(微网站.LBS云.Api接口调用.服务号高级接口) 课程下载地址:链接:http://pan.baidu.com/share/link?shareid=2214724072&uk=3611155194 密码:glvc 一.本课程是怎么样的一门课程(全面介绍) 1.1.课程的背景 微信公众平台的火热程度已经不用多言,无论是个人还是企业,政府还是商家,都已经开始搭建微信公众平台,微信的作用已经被各界人士认可.微信公众平台的技术需求市场缺口巨大. 1.2.课程内容简介 本

Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明

这里所说的高级接口是指面向通过认证的服务号开通的高级功能. 高级功能大致可以分类为: 用户接口 分组接口 客服接口(有别于之前介绍的多客服) 群发接口 多媒体接口 二维码接口 模板消息接口(不是所有账号都可开通) OAuth2.0(相对比较复杂,后面会有专门介绍) 以上所有的接口都包含在Senparc.Weixin.MP.AdvancedAPIs命名空间下. 一些共同的操作 几乎所有的高级接口都需要用到AccessToken来通讯(注意,下面如果没有特殊说明的接口都需要这个AccessToken

10第十章数据修改高级用法(转载)

10第十章数据修改高级用法 MERGE OUPUT $action AS action  (由这个动作来判断是inserted 还是 deleted) WHEN MATCHED AND (源.列 <> 目.列) 才更新 WHEN NOT MATCHED BY SOURCE THEN DELETE (慎用) WHEN NOT MATCHED THEN INSERT VALUES 在 2008 之前 插入多条 需要写多个insert values 08 之后可以下载一起 @rowcount = @

微信公众平台自定义菜单及高级接口PHP SDK

本文介绍介绍微信公众平台自定义菜单及高级接口的PHP SDK及使用方法. 作者 方倍工作室 修正记录: 2014.05.03 v1.0 方倍工作室 http://www.cnblogs.com/txw1958/ SDK 源码: 1 /* 2 方倍工作室 http://www.cnblogs.com/txw1958/ 3 CopyRight 2014 www.doucube.com All Rights Reserved 4 */ 5 6 class class_weixin_adv 7 { 8

微信公众平台开放 9 大高级接口,它有什么意义?

微信刚刚更新公众平台,向服务号开放微信认证,开放 9 大高级接口,增加开发者问答系统,并对微信公众平台的后台管理界面进行改版. 其中最受关注的是微信向开发者开放的九大高级接口.这些接口为: 语音识别接口 客服接口 OAuth2.0 网页授权接口 生成带参数的二维码接口 获取用户地理位置接口 获取用户基本信息接口 获取关注者列表接口 用户分组接口 上传下载多媒体文件接口 上图中,微信官方对九大接口作了详细的介绍.我们一起来看看微信开放这些接口有什么意义. 1. 语音识别 描述:通过语音识别接口,用

微信公众平台无高级接口账号获取用户基本信息

获得微信公众平台关注用户的基本信息,包括昵称.头像.性别.国家.省份.城市.语言. 有两个不同的Access Token,他们产生的方式不一样, 一种是使用AppID和AppSecret获取的access_token, 一种是OAuth2.0授权中产生的access_token,方倍工作室分别称为全局Access Token和授权Access Token. 网页授权的两种scope的区别说明 1.以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是

C#微信公众号接口开发实例-高级接口-申请带参数的二维码

最近公司涉及到微信绑定用户,做了高级接口-申请带参数的二维码,总结了下微信开发接口.微信接口开发都是除了消息用的xml 回复基本上都是用json的形式传递信息(post/get),开发的方法基本都是一样的,以下以高级接口获取带参数的二维码为例,怎么做微信接口开发. 第一步:获取access_token,access_token是获取其他接口信息的钥匙,所有接口都需要调用access_token /// <summary> /// 拉取AccessToken,微信每天公共2000次AccessT

微信公众平台开发 无高级接口账号获取用户基本信息(转)

本文介绍如何获得微信公众平台关注用户的基本信息,包括昵称.头像.性别.国家.省份.城市.语言.本文的方法将囊括订阅号和服务号以及自定义菜单各种场景,无论是否有高级接口权限,都有办法来获得用户基本信息,而无需模拟登录. 在本文中,特别要注意的是有两个不同的Access Token,他们产生的方式不一样,一种是使用AppID和AppSecret获取的access_token,一种是OAuth2.0授权中产生的access_token,方倍工作室分别称为全局Access Token和授权Access