作一个图像类相关的APP也有九个多月了(没事别乱点),大部分时间都是在开发中学习。如今回头系统性地补一下iOS的图像处理知识。笔者此段时间也同时在写毕业论文,可能想到哪里写到哪里。这一系列文章可能包含如下内容(暂时构思):git
UIImage:github
在全部表明图片的各类类型中,来自UIKit的 UIImage 应该是开发者接触最多的高阶图片对象,同时UIImage也提供了各类各样的方法来处理图片。UIImage是不可变对象,这意味着开发者不能直接修改图片的Metadata(what is Metadata?),也不能直接访问图片的底层数据格式,好处也有,也就是UIImage是线程安全的。另一点,和UIImage最配对的莫过于UIImageView。算法
须要注意的是,UIImage不适合承载太大的尺寸。在内存不足的时候,UIImage中的数据可能会被系统清理掉(不是UIImage,而是它包含的数据),而后在再次须要的时候UIImage会从新加载数据,这种步骤可能会带来一些性能上的影响。开发者最好避免建立大于1024 x 1024 大小的UIImage。大尺寸的图片除了消耗大量的内存,在使用图片做为纹理在OpenGL ES中渲染或者在view或者layer上重画的时候可能会遇到性能问题。swift
若是真的须要操做很大的图片,以Bitmap形式在Graphics context中处理会是不错的选择。另一种显示大图的方式就是拆成几张小图再使用(听起来手术床有点复杂?)。缓存
咱们先看看读取UIImage的一个方法(Dikey尝试投入Swift):安全
init?(named name: String) -> UIImage
关于这个方法,咱们须要记住的有几点。第一点就是这个方法是默认会加载图片到系统缓存的。若是图片只用到一次,开发者应该用init(contentsOfFile:) 代替。第二点可能你们都知道,就是在Retina上,这个方法默认会在imageName后面加上@2x或者@3x(依据屏幕scale而定)。另外,若是是png文件,那读取的时候后缀能够省略。app
CGImage:框架
说到bitmap,那CGImageRef就应该出场了。CGImageRef 就是对bitmap image/bitmap image masks的一种封装。bitmap包含源图片每个像素点的信息,因此在底层处理图片就少不了和它打交道了。CG的前缀还表明着C,而后须要手动释放内存……底层、复杂固然还有高效。简单看一个建立方法: ide
func CGImageCreate(_ width: Int, _ height: Int, _ bitsPerComponent: Int, _ bitsPerPixel: Int, _ bytesPerRow: Int, _ colorspace: CGColorSpace!, _ bitmapInfo: CGBitmapInfo, _ provider: CGDataProvider!, _ decode: UnsafePointer<CGFloat>, _ shouldInterpolate: Bool, _ intent: CGColorRenderingIntent) -> CGImage!
让咱们来逐项解析参数:性能
width |
宽度 |
height |
高度 |
bitsPerComponent |
每一个像素对应的Componet对应的位宽. 举例: RGBA-32 格式,须要component须要8bits |
bitsPerPixel |
所须要的bits值(和参数名是否是不大匹配?). bitsPerPixel>= bitsPerComponent*bitsPerComponent的bit值 |
bytesPerRow |
每一行占用的内存 |
colorspace |
色彩空间, Quartz 会持有它,再返回以后可能须要手动释放 |
bitmapInfo |
CGBitmapInfo 决定了bitmap是否须要保存 alpha 渠道、bitmap的相对像素位置, 色彩份量是 floating或integer相关. |
provider |
bitmap的数据源. 由Quartz持有; 需手动释放. |
decode |
图片解压以后的数据。不须要从新映射色值,传NULL。对于每种空间中的色彩份量,decode array的值都有上下限制。在RGB色域中,decode array一共提供6个entries,分别对应RGB的上下限。当一张图片被渲染以后,Quartz使用一个线性转变,将原始的色彩份量值转成操做色彩空间中的数值。 |
shouldInterpolate |
是否容许interpolation(插值)。是的话,Quartz会对图片使用像素平滑算法。假如为NO,图片在使用在比本身的分辨率高的设备上时可能会显示出锯齿。 |
intent |
当一些颜色不在graphics context的目标色彩空间的色域中的时候,intent(再现意图)决定了Quartz如何处理这些颜色。rendering intent会使用肯定的方法对色彩映射,进行空间转换。更详细的须要参考苹果文档:Color Rendering Intents. |
在底层处理bitmap,是一件不容易的事情,须要和了解不少与数字图像处理相关的概念,这里暂不深刻讨论。Core Graphics是基于C的API,和Objective-C交互多是更直接的方式。这里有一个很好的UIImage、bitmap互转的示例 ,也许在Swift中,C混合Objective-C而后桥接至Swift是不错的方式。
CIImage:
CIImage表明了Core Image中的一张图片,注意仅仅是表明,虽然CIImage包含图片相关的数据,实际上它不是一张图片。CIImage是不可变类型,意味着线性安全,Core Image 经过CIImage的数据进行惰性渲染,带来更高效的资源利用。
什么是惰性渲染?举个栗子,对CIImage进行各类操做,并不直接产生渲染效果。只有好比,真正要求生成一张UIImage,这个时候CIImage就懂了。懒懒地提供了一张UIImage,现制的。
CIImage 之于iOS的做用,有点像是Dota中的全能。苹果提供了滤镜、剪切、旋转等等功能,而实际上以上功能可能均可以用其余各类方式实现。也许较好的封装和高效是加分项。
ALAsset/PHAsset
看他们名字就知道他们很像,实际上,他们就是iOS在不一样时代的两架马车,担当了对Photos中的资源的读写中介人。不得不说这几年apple的精力确实在iOS端比Mac OS X端多得多。Mac端的Photos是在10.10才替换的,而iOS上则更早一点。
ALAsset中AL表明AssetsLibrary,PHAsset中PH表明来自Photos框架。Photos框架中大量出现block,另外在照片读取的时候,缓存也被各类设计好。更快、更好、更安全这句Swift的广告词扔在Photos框架中毫无违和感。不过也有不足的地方,缺点之一是iOS8以后才出现Photos框架,你要么扔掉iOS8之前的用户吧,要么你维护两套代码吧。另一个缺点是Photos框架因为很新,在初期深刻使用的时候可能会发现各类bug。这两个不大的缺点意味着在将来,Photos将是对Photos APP中的资源进行操做的不二选择。
从新忘记ALAsset,PHAsset表明了iOS Photos App中的资源对象:包括图片、视频以及iCloud内容。做为Photos框架中的一员,PHAsset只是进行其中的一个小小环节,获取真正的图片还须要配合PHImageManager等等才能读取、缓存UIImage,利用PHFetchResults管理批量的PHAsset等等。PHAsset的最好展现:iOS8+的Photos。
实际上,各类各样的格式,只是恰到好处地表明图片出如今了各类使用场合。而咱们只有在理解背后的框架以后才能在各类场合对图片选择正确的处理方式。这一篇简单介绍一些平时iOS开发可能会碰到的一些与图片相关的格式。
下一章,咱们会去了解一下各类格式它们所在的框架。