请求图像(这里有巨坑)
关于PHImageManager
类,NSHipster 有篇总结文章不错。
- requestImageForAsset:targetSize:contentMode:options:resultHandler:
你不应该生成该类的实例,而应该使用该类的提供的单例对象。该方法提供指定的尺寸的图像,与ALAssetsLibrary
库相比,没有了方便的缩略图提供。不过要吐槽的是,ALAssetsLibrary
库提供的缩略图往往尺寸太小并且质量很低,用在 TableView 上还可以。
需要注意的是,该方法在默认情况下是异步执行的,而且 Photos 库可能会多次执行 resultHandler 块,因为对于指定的尺寸,Photos 可能会先提供低质量的图像以供临时显示,随后会将指定尺寸的图像返回。如果指定尺寸的高质量的图像有缓存,那么直接提供高质量的图像。而这些行为,可以通过 options 参数来定制。
PHImageRequestOptions
类用于定制请求。这里有巨坑。上面的方法返回指定尺寸的图像,如果你仅仅指定必要的参数而没有对 options 进行配置的话,返回的图像尺寸将会是原始图像的尺寸。或者,你指定的尺寸很小,这时候会按照你的要求来返回接近该尺寸的图像。在我的 iPad mini 一代上,对于自拍的图像,指定尺寸不超过(257, 257)的话,返回的图像尺寸和你预期的一样,其他情况下都是原始尺寸。PHImageRequestOptions
有以下几个重要的属性:
synchronous:指定请求是否同步执行。
resizeMode:对请求的图像怎样缩放。有三种选择:None,不缩放;Fast,尽快地提供接近或稍微大于要求的尺寸;Exact,精准提供要求的尺寸。
deliveryMode:图像质量。有三种值:Opportunistic,在速度与质量中均衡;HighQualityFormat,不管花费多长时间,提供高质量图像;FastFormat,以最快速度提供好的质量。
这个属性只有在 synchronous 为 true 时有效。
normalizedCropRect:用于对原始尺寸的图像进行裁剪,基于比例坐标。只在 resizeMode 为 Exact 时有效。
resizeMode 默认是 None,这也造成了返回图像尺寸与要求尺寸不符。这点需要注意。要返回一个指定尺寸的图像需要避免两层陷阱:一定要指定 options 参数,resizeMode 不能为 None。
除了必有的请求图像或是视频的功能外,PHImageManager
添加了两大功能:
1.缓存图像,由其子类PHCachingImageManager
实现,缓存效率和空间管理能满足大部分场景的需求;
2.裁剪图像,这个功能很久以前就有强烈的需求。六年前 StackOverflow 上 Cropping a UIImage 这个问题就被提出来了,方法也五花八门,然而这些方法可能会有各种小问题。官方的方法能让你避免这些小问题。使用方法可以参考 NSHipster 的总结文章里用人脸识别获取头像的例子。
(1)PHImageRequestOptions 与 iCloud 照片库
PHImageRequestOptions 中包含了一系列控制请求图像的属性。
resizeMode 属性控制图像的剪裁,不知道为什么 PhotoKit 会在请求图像方法(requestImageForAsset)中已经有控制图像剪裁的参数后(contentMode),还在 options 中加入控制剪裁的属性,但如果两个地方所控制的剪裁结果有所冲突,PhotoKit 会以 resizeMode 的结果为准。另外,resizeMode 也有控制图像质量的作用。如 resizeMode 设置为 PHImageRequestOptionsResizeModeExact 则返回图像必须和目标大小相匹配,并且图像质量也为高质量图像,而设置为 PHImageRequestOptionsResizeModeFast 则请求的效率更高,但返回的图像可能和目标大小不一样并且质量较低。
在 PhotoKit 中,对 iCloud 照片库有很好的支持,如果用户开启了 iCloud 照片库,并且选择了“优化 iPhone/iPad 储存空间”,或者选择了“下载并保留原件”但原件还没有加载好的时候,PhotoKit 也会预先拿到这些非本地图像的 PHAsset,但是由于本地并没有原图,所以如果产生了请求高清图的请求,PHotoKit 会尝试从 iCloud 下载图片,而这个行为最终的表现,会被 PHImageRequestOptions 中的值所影响。PHImageRequestOptions 中常常会用的几个属性如下:
networkAccessAllowed 参数控制是否允许网络请求,默认为 NO,如果不允许网络请求,那么就没有然后了,当然也拉取不到 iCloud 的图像原件。deliveryMode 则用于控制请求的图片质量。synchronous 控制是否为同步请求,默认为 NO,如果 synchronous 为 YES,即同步请求时,deliveryMode 会被视为 PHImageRequestOptionsDeliveryModeHighQualityFormat,即自动返回高质量的图片,因此不建议使用同步请求,否则如果界面需要等待返回的图像才能进一步作出反应,则反应时长会很长。
还有一个与 iCloud 密切相关的属性 progressHandler,当图像需要从 iCloud 下载时,这个 block 会被自动调用,block 中会返回图像下载的进度,图像的信息,出错信息。开发者可以利用这些信息反馈给用户当前图像的下载进度以及状况,但需要注意 progressHandler 不在主线程上执行,因此在其中需要操作 UI,则需要手工放到主线程执行。
上面有提到,requestImageForAsset 中的参数 resultHandler 可能会被多次调用,这种情况就是图像需要从 iCloud 中下载的情况。在 requestImageForAsset 返回的内容中,一开始的那一次请求中会返回一个小尺寸的图像版本,当高清图像还在下载时,开发者可以首先给用户展示这个低清的图像版本,然后 block 在多次调用后,最终会返回高清的原图。至于当前返回的图像是哪个版本的图像,可以通过 block 返回的 NSDictionary info 中获知,PHImageResultIsDegradedKey 表示当前返回的 UIImage 是低清图。如果需要判断是否已经获得高清图,可以这样判断:
1
2
|
// 排除取消,错误,低清图三种情况,即已经获取到了高清图
BOOL
downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];
|
另外,当我们使用 requestImageForAsset 发出对图像的请求时,如果在同一个 PHImageManager 中同时对同一个资源发出图像请求,请求的进度是可以共享的,因此我们可以利用这个特性,把 PHImageManager 以单例的形式使用,这样在切换界面时也不用担心无法传递图像的下载进度。例如,在图像的列表页面触发了下载图像,当我们离开列表页面进入预览大图界面时,并不用担心会重新图像会重新下载,只要没有手工取消图像下载,进入预览大图界面下载图像会自动继续从上次的进度下载图像。
如果希望取消下载图像,则可以使用 PHImageManager 的 cancelImageRequest 方法,它传入的是请求图像的请求 ID,这个 ID 可以从 requestImageForAsset 的返回值中获得,也可以从前面提到的包含图像信息的 NSDictionary info 中获得,当然前提是这个这个接收取消请求的 PHImageManager 与刚刚发出请求的 PHImageManager 是同一个实例,如上面所述使用单例是最为简单有效的方式。
最后,还要介绍一个 PHImageRequestOptions 的属性 versions,这个属性是指获取的图像是否需要包含系统相册“编辑”功能处理过的信息(如滤镜,旋转等),这一点比 ALAssetLibrary 要灵活很多,ALAssetLibrary 中并不能灵活地控制获取的图像是否带有“编辑”处理过的效果,例如在 ALAsset 中获取原图的接口 fullResolutionImage 获取到的是不带“编辑”效果的图像,要想获取带有“编辑”效果的图像,只能自行处理获取这些滤镜效果,并手工叠加上去。在我们的 UI 框架 QMUI 中就有对获取原图作出这样的封装,整个过程也较为繁琐,而框架中处理 PhotoKit 的部分则灵活很多,这也体现了 PhotoKit 相比 ALAssetLibrary 的最主要特点——复杂但灵活。文章的第三部分也会详细列出如何处理这个问题。
[GetImage]1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
由于获取图片的方法默认是异步的,所以代码中提供了取消上次加载图片的方法。有关PHImageManager 的其他内容,大家可以自行查看文档。这里就完成了从Photos中获取所有图片的方法。
STKitDemo中也提供了STImagePickerController,当然目前STKit还由于一些不稳定因素没有public,大家可以先行体验一下。STKitDemo下载地址。操作步骤,进入主页之后点击图片选择。
http://mobile.51cto.com/iphone-468433.htm
每天,用 iPhone 拍摄的照片数量超过了任何相机。每年 iOS 设备上的显示效果变得越来越好,回到 iPad 刚出现还没有 Retina 显示屏的时代,大屏幕的杀手级功能之一就是可以展示用户照片和浏览器照片库。自从相机成为 iPhone 最重要和最受欢迎的功能开始,对能管理和加工用户照片库中宝贵的照片的应用程序和工具就有着巨大的需求。