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); |