ImageIO

0x00 前言
这篇文章是自己在学习 CFHipsterRef Chapter 8 ImageIO 时做的笔记。
0x01 ImageIO
Image I/O 是一个强大的,虽然不太知名的图像处理框架。独立于 Core Graphics,它可以在许多不同格式之间读写,访问照片元数据,并执行常见的图像处理操作。这个框架提供了平台上最快的图像编码器和解码器,具有高级缓存机制,甚至能够增量地加载图像。
0x02 Supported Image Types
根据官网文档,Image I/O 支持 “大多数图像格式”。与其拿文档来看,还不如用代码的方式来获取。
CGImageSourceCopyTypeIdentifiers 返回支持的图像类型的 UTI 列表:
Image I/O UTIs
| UTI | iOS | OS X |
|---|---|---|
| com.adobe.photoshop-image | x | |
| com.adobe.raw-image | x | x |
| com.apple.icns | x | |
| com.apple.macpaint | x | |
| com.apple.pict | x | |
| com.apple.quicktime-image | x | |
| com.canon.cr2-raw-image | x | x |
| com.canon.crw-raw-image | x | x |
| com.canon.tif-raw-image | x | x |
| com.compuserve.gif | x | x |
| com.epson.raw-image | x | x |
| com.fuji.raw-image | x | x |
| com.hasselblad.3fr-raw-image | x | x |
| com.hasselblad.fff-raw-image | x | x |
| com.ilm.openexr-image | x | |
| com.kodak.flashpix-image | x | |
| com.kodak.raw-image | x | x |
| com.konicaminolta.raw-image | x | x |
| com.leafamerica.raw-image | x | x |
| com.leica.raw-image | x | x |
| com.leica.rwl-raw-image | x | x |
| com.microsoft.bmp | x | x |
| com.microsoft.cur | x | x |
| com.microsoft.ico | x | x |
| com.nikon.nrw-raw-image | x | x |
| com.nikon.raw-image | x | x |
| com.olympus.or-raw-image | x | x |
| com.olympus.raw-image | x | x |
| com.olympus.sr-raw-image | x | x |
| com.panasonic.raw-image | x | x |
| com.panasonic.rw2-raw-image | x | x |
| com.pentax.raw-image | x | x |
| com.samsung.raw-image | x | x |
| com.sgi.sgi-image | x | |
| com.sony.arw-raw-image | x | x |
| com.sony.raw-image | x | x |
| com.sony.sr2-raw-image | x | x |
| com.truevision.tga-image | x | x |
| public.jpeg | x | x |
| public.jpeg-2000 | x | x |
| public.mpo-image | x | |
| public.png | x | x |
| public.radiance | x | |
| public.tiff | x | x |
| public.xbitmap-image | x | x |
事实证明,这似乎是 大多数 格式。至少是那些对现在应用程序重要的。普遍支持常见格式:TIFF,JPEG,GIF,PNG,RAW 和 Windows Bitmap,Icon 和 Cursor。另外,在 iOS 上支持多种供应商特定的 RAW 摄像机格式,不过 OS X 还支持其他几种格式。
0x03 Writing to a file
Image I/O 提供了高级输出配置,不需要很多开销。
指定期望输出格式的 UTI 以及任何选项,如压缩质量,方向或是否忽略 Alpha 通道。为目标创建一个 CGImageDestinationRef,将 CGImage 添加到其中,然后进行最终化(finalized):
1 | UIImage *image = ...; |
0x04 Reading from a File
从一个文件中读取一张图像的过程也非常相似。
创建一个期望的输出文件的 file URL,并设置任何所需的缓存标记或图像类型提示。使用这个 URL 创建一个 CGImageSourceRef,然后调用 CGImageSourceCreateImageAtIndex 读取数据并创建一个 CGImage。
1 | NSURL *fileURL = [NSURL fileURLWithPath:@"/path/to/input.jpg"]; |
0x05 Incrementally Reading an Image
前面的示例可以被扩展一下成为增量加载图像,这可以为加载特别大或远程图像提供一个更好的用户体验。
由于很多应用程序通过 HTTP 来加载图像,session task delegate 方法 URLSession:dataTask:didReceiveData: 是一个性能增益(performance gains)非常好的机会:
1 | - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask disReceiveData:(NSData *)data { |
给定一个 CGImageSourceRef,它将会在请求开始加载时被初始化,这个 delegate 方法调用 CGImageSourceUpdateData 用响应数据缓冲区(response data buffer)更新。
如果已经加载了足够的数据来确定图像的最终尺寸,CGImageSourceCopyPropertiesAtIndex 可以检索该信息并对其进行高速缓存。从那时起,一个 delegate 或 block 回调将能够发送部分加载的图像以更新主线程上的 UI。
0x06 Image Metadata
在增量图像加载示例中,从其元数据中检索到图像的宽和高,以便可以正确地调整大小 – 即使在所有数据加载之前。
可以使用相同的方法检索图像元数据,诸如 GPS 数据(位置),相机 EXIF(透镜,曝光,快门速度等),或 IPTC(information suitable for publication,创作者和版权)。
元数据被分为几个不同的字典,可以用以下任意 key 来指定:
- kCGImagePropertyTIFFDictionary
- kCGImagePropertyGIFDictionary
- kCGImagePropertyJFIFDictionary
- kCGImagePropertyExifDictionary
- kCGImagePropertyPNGDictionary
- kCGImagePropertyIPTCDitionary
- kCGImagePropertyGPSDictionary
- kCGImagePropertyCIFFDictionary
- kCGImageProperty8BIMDictionary
- kCGImagePropertyDNGDictionary
- kCGImagePropertyExifAuxDictionary
使用 Image I/O 检索图像元数据属性是相当不言自明的:一个调用 CGImageSourceCopyPropertiesAtIndex,从此刻开始它是在 CGImageProperty keys 上所有标准 NSDictionary 访问(it’s all standard NSDictionary access on CGImageProperty keys from there on out):
1 | NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(self.imageSourceRef, 0, NULL); |