008 [iOS图像]一、iOS中的那些图片格式

      做一个图像类相关的APP也有九个多月了(没事别乱点),大部分时间都是在开发中学习。现在回头系统性地补一下iOS的图像处理知识。笔者此段时间也同时在写毕业论文,可能想到哪里写到哪里。这一系列文章可能包含以下内容(暂时构思):

  • iOS中图片的各种格式初探
  • iOS中图片处理的各种框架浅析
  • iOS图片处理的那些好用的第三方

iOS中图片的各种格式初探

UIImage:

      在所有代表图片的各种类型中,来自UIKit的 UIImage 应该是开发者接触最多的高阶图片对象,同时UIImage也提供了各种各样的方法来处理图片。UIImage是不可变对象,这意味着开发者不能直接修改图片的Metadata(what is Metadata?),也不能直接访问图片的底层数据格式,好处也有,也就是UIImage是线程安全的。另外一点,和UIImage最配对的莫过于UIImageView。

      需要注意的是,UIImage不适合承载太大的尺寸。在内存不足的时候,UIImage中的数据可能会被系统清理掉(不是UIImage,而是它包含的数据),然后在再次需要的时候UIImage会重新加载数据,这种步骤可能会带来一些性能上的影响。开发者最好避免创建大于1024 x 1024 大小的UIImage。大尺寸的图片除了消耗大量的内存,在使用图片作为纹理在OpenGL ES中渲染或者在view或者layer上重画的时候可能会遇到性能问题。

      如果真的需要操作很大的图片,以Bitmap形式在Graphics context中处理会是不错的选择。另外一种显示大图的方式就是拆成几张小图再使用(听起来手术床有点复杂?)。

      我们先看看读取UIImage的一个方法(Dikey尝试投入Swift):

init?(named name: String) -> UIImage  

  关于这个方法,我们需要记住的有几点。第一点就是这个方法是默认会加载图片到系统缓存的。如果图片只用到一次,开发者应该用init(contentsOfFile:) 代替。第二点可能大家都知道,就是在Retina上,这个方法默认会在imageName后面加上@2x或者@3x(依据屏幕scale而定)。另外,如果是png文件,那读取的时候后缀可以省略。

 

CGImage:

      说到bitmap,那CGImageRef就应该出场了。CGImageRef 就是对bitmap image/bitmap image masks的一种封装。bitmap包含源图片每一个像素点的信息,所以在底层处理图片就少不了和它打交道了。CG的前缀还代表着C,然后需要手动释放内存……底层、复杂当然还有高效。简单看一个创建方法:      

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代表AssetsLibraryPHAsset中PH代表来自Photos框架。Photos框架中大量出现block,另外在照片读取的时候,缓存也被各种设计好。更快、更好、更安全这句Swift的广告词扔在Photos框架中毫无违和感。不过也有不足的地方,缺点之一是iOS8之后才出现Photos框架,你要么扔掉iOS8以前的用户吧,要么你维护两套代码吧。另外一个缺点是Photos框架由于很新,在初期深入使用的时候可能会发现各种bug。这两个不大的缺点意味着在未来,Photos将是对Photos APP中的资源进行操作的不二选择。

      重新忘记ALAssetPHAsset代表了iOS Photos App中的资源对象:包括图片、视频以及iCloud内容。作为Photos框架中的一员,PHAsset只是进行其中的一个小小环节,获取真正的图片还需要配合PHImageManager等等才能读取、缓存UIImage,利用PHFetchResults管理批量的PHAsset等等。PHAsset的最好展示:iOS8+的Photos。

 

小结:

      实际上,各种各样的格式,只是恰到好处地代表图片出现在了各种使用场合。而我们只有在理解背后的框架之后才能在各种场合对图片选择正确的处理方式。这一篇简单介绍一些平时iOS开发可能会碰到的一些与图片相关的格式。

     下一章,我们会去了解一下各种格式它们所在的框架。

 

 

 

 

posted @ 2015-08-24 17:01  Dikey  阅读(685)  评论(0编辑  收藏  举报