iOS开发日记56-详解UIImage

今天博主有一个图片及处理的需求,遇到了一些困难点,在此和你们分享,但愿可以共同进步.python

UIImage对象是iOS中用来显示图像数据的高级接口。咱们能够从文件,NSData,Quartz图片对象中建立UIImage对象。能够说这个类是咱们接触频率很是高的一个类。ios

UIImage的不可变性

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

若是咱们想修改UIImage对象的一些属性,则可使用便捷方法和自定义的参数值来建立图像的一份拷贝。数组

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

let image = UIImage(named: "swift"); let imageData:NSData? = UIImageJPEGRepresentation(image!, 1.0)

建立UIImage对象

对于一个UIImage对象来讲,它的数据源主要有如下几种:安全

  1. 文件:咱们可使用init(contentsOfFile:)方法来从指定文件中建立对象。ruby

  2. 纯图片数据(NSData):若是在内存中有图片的原始数据(表示为NSData对象),则可使用init(data:)来建立。须要注意的是这个方法会对象图片数据作缓存。app

  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提供了以下方法来执行此操做:

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

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

在iOS 5中,咱们可使用如下方法来执行相同的操做:

func resizableImageWithCapInsets(_ capInsets: UIEdgeInsets) -> UIImage

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

咱们对上面的图片作以下处理:

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参数,容许咱们指定拉伸模式。

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

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

动效图片对象

若是咱们有一组大小和缩放因子相同的图片,就能够将这些图片加载到同一个UIImage对象中,造成一个动态的UIImage对象。为此,UIImage提供了如下方法:

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

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

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

  1. 文件的序号必须是从0开始的连续数字,若是不从0开始,则在Playground中是会报错的。而若是中间序号有断,而中断后的图片是不会被加载的。

  2. 全部文件的大小和缩放因子应该是相同的,不然显示时会有不可预期的结果,这种结果主要表现为播放的顺序多是杂乱的。

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

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

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

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

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格式

 

http://blog.ibireme.com/2015/11/02/ios_image_tips/

相关文章
相关标签/搜索