翻译自:Image I/O Programming Guide(更新时间:2016-09-13
https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/ImageIOGuide/imageio_intro/ikpg_intro.html#//apple_ref/doc/uid/TP40005462
文章目录
- 一、介绍
- 1、谁应该阅读本文档?
- 2、本文档的组织
- 3、也可以看看
- 二、使用Image I/O 的基础知识
- 1、在应用程序中使用Image I/O 框架
- 2、支持的图像格式
- 三、创建和使用图像源
- 1、从图像源创建图像
- 2、从图像源创建缩略图
- 3、逐步加载图像
- 4、显示图像属性
- 四、使用图像目标
- 1、设置图像目标的属性
- 2、将图像写入图像目标
- 3、创建动画图像
一、介绍
Image I/O 编程接口允许应用程序读取和写入大多数图像文件格式。
Image I/O 最初是 Core Graphics 框架的一部分,它位于自己的框架中,允许开发人员独立于 Core Graphics (Quartz 2D) 使用它。
Image I/O 提供了访问图像数据的权威方法,因为它效率高、允许轻松访问元数据并提供颜色管理。
Image I/O 接口在 OS X v10.4 及更高版本以及 iOS 4 及更高版本中可用。
1、谁应该阅读本文档?
本文档适用于在应用程序中读取或写入图像数据的开发人员。
任何当前使用图像导入器或其他图像处理库的开发人员都应阅读本文档以了解如何使用Image I/O 框架。
2、本文档的组织
本文档分为以下章节:
- 《使用Image I/O 的基础知识》讨论了支持的图像格式并展示了如何将框架包含在 Xcode 项目中。
- 创建和使用图像源展示了如何创建图像源、从中创建图像以及提取属性以在用户界面中显示。
- 使用图像目标提供了有关创建图像目标、设置其属性以及向其中添加图像的信息。
3、也可以看看
图像 I/O 参考集 提供了Image I/O 框架中的函数、数据类型和常量的详细描述。
二、使用Image I/O 的基础知识
Image I/O 框架提供不透明数据类型,用于从源 ( CGImageSourceRef
) 读取图像数据 并将图像数据写入目标 ( CGImageDestinationRef
)。
它支持多种图像格式,包括标准 Web 格式、高动态范围图像和原始相机数据。
Image I/O 具有许多其他功能,例如:
- Mac 平台上最快的图像解码器和编码器
- 逐步加载图像的能力
- 支持图像元数据
- 有效缓存
您可以从以下位置创建图像源和图像目标对象:
- URL。 图像位置可以用 URL 指定,可以充当图像数据的提供者或接收者。
在 Image I/O 中,URL 表示为 Core Foundation 数据类型CFURLRef
。 - 核心基础对象
CFDataRef
和CFMutableDataRef
。 - Quartz 数据消费者(
CGDataConsumerRef
)和数据提供者(CGDataProviderRef
)对象。
1、在应用程序中使用Image I/O 框架
Image I/O 位于 OS X 中的 Application Services 框架以及 iOS 中的 Image I/O 框架中。
将框架添加到应用程序后,通过包含以下语句来导入头文件:
#import <ImageIO/ImageIO.h>
2、支持的图像格式
Image I/O 框架可理解大多数常见的图像文件格式,例如 JPEG、JPEG2000、RAW、TIFF、BMP 和 PNG。
并非所有格式都在每个平台上都受支持。
如需获取 Image I/O 支持的最新列表,您可以调用以下函数:
CGImageSourceCopyTypeIdentifiers
返回Image I/O 支持,作为图像源的统一类型标识符(UTI) 数组。CGImageDestinationCopyTypeIdentifiers
,返回 Image I/O 支持,作为图像目标的统一类型标识符 (UTI) 数组。
然后,您可以使用该CFShow
函数 将数组打印到 Xcode 中的调试器控制台,如例 1-1所示。
这些函数返回的数组中的字符串采用 com.apple.pict
、public.jpeg
和public.tiff
等形式。
表 1-1 列出了许多常见图像文件格式的UTI。
OS X 和 iOS 为大多数常见图像文件格式,定义了常量;完整的常量集在 UTCoreTypes.h
头文件中声明。
当您需要指定图像类型时,可以使用这些常量,作为图像源的提示(kCGImageSourceTypeIdentifierHint
)或作为图像目标的图像类型。
例 1-1 获取和打印支持的 UTI
CFArrayRef mySourceTypes = CGImageSourceCopyTypeIdentifiers();
CFShow(mySourceTypes);
CFArrayRef myDestinationTypes = CGImageDestinationCopyTypeIdentifiers();
CFShow(myDestinationTypes);
Uniform type identifier | Image content type constant |
---|---|
public.image | kUTTypeImage |
public.png | kUTTypePNG |
public.jpeg | kUTTypeJPEG |
public.jpeg-2000 (OS X only) | kUTTypeJPEG2000 |
public.tiff | kUTTypeTIFF |
com.apple.pict (OS X only) | kUTTypePICT |
com.compuserve.gif | kUTTypeGIF |
三、创建和使用图像源
图像源抽象了数据访问任务,无需您通过原始内存缓冲区管理数据。
图像源可以包含多个图像、缩略图、每个图像的属性以及图像文件。
当您使用图像数据并且您的应用程序在 OS X v10.4 或更高版本中运行时,图像源是将图像数据移动到您的应用程序中的首选方式。
创建CGImageSource
对象后,您可以使用*CGImageSource 参考* 中描述的函数获取图像、缩略图、图像属性和其他图像信息。
1、从图像源创建图像
使用Image I/O 框架执行的最常见任务之一是从图像源创建图像,类似于例 2-1中所示的内容。
此示例显示如何从路径名创建图像源,然后提取图像。
创建图像源对象时,您可以提供有关图像源文件格式的提示。
从图像源创建图像时,必须指定索引,并且可以提供属性字典(键值对)来指定是否创建缩略图或允许缓存等内容。
CGImageSource参考 和 CGImageProperties 参考 列出了键以及每个键的值的预期数据类型。
您需要提供索引值,因为某些图像文件格式允许多个图像驻留在同一个源文件中。
对于仅包含一个图像的图像源文件,请传递0
。
您可以通过调用 CGImageSourceGetCount
函数 来找出图像源文件中的图像数量。
例 2-1 从图像源创建图像
CGImageRef MyCreateCGImageFromFile (NSString* path)
{
// Get the URL for the pathname passed to the function.
NSURL *url = [NSURL fileURLWithPath:path];
CGImageRef myImage = NULL;
CGImageSourceRef myImageSource;
CFDictionaryRef myOptions = NULL;
CFStringRef myKeys[2];
CFTypeRef myValues[2];
// Set up options if you want them. The options here are for
// caching the image in a decoded form and for using floating-point
// values if the image format supports them.
myKeys[0] = kCGImageSourceShouldCache;
myValues[0] = (CFTypeRef)kCFBooleanTrue;
myKeys[1] = kCGImageSourceShouldAllowFloat;
myValues[1] = (CFTypeRef)kCFBooleanTrue;
// Create the dictionary
myOptions = CFDictionaryCreate(NULL, (const void **) myKeys,
(const void **) myValues, 2,
&kCFTypeDictionaryKeyCallBacks,
& kCFTypeDictionaryValueCallBacks);
// Create an image source from the URL.
myImageSource = CGImageSourceCreateWithURL((CFURLRef)url, myOptions);
CFRelease(myOptions);
// Make sure the image source exists before continuing
if (myImageSource == NULL){
fprintf(stderr, "Image source is NULL.");
return NULL;
}
// Create an image from the first item in the image source.
myImage = CGImageSourceCreateImageAtIndex(myImageSource,
0,
NULL);
CFRelease(myImageSource);
// Make sure the image exists before continuing
if (myImage == NULL){
fprintf(stderr, "Image not created from image source.");
return NULL;
}
return myImage;
}
2、从图像源创建缩略图
某些图像源文件包含您可以检索的缩略图。
如果尚未存在缩略图,Image I/O 会为您提供创建缩略图的选项。
您还可以指定最大缩略图大小以及是否对缩略图应用变换。
例 2-2显示了如何从数据创建图像源,设置包含与缩略图相关的选项的字典,然后创建缩略图。
您可以使用kCGImageSourceCreateThumbnailWithTransform
键来指定,是否应旋转和缩放缩略图以匹配完整图像的方向和像素纵横比。
例 2-2 创建缩略图
CGImageRef MyCreateThumbnailImageFromData (NSData * data, int imageSize)
{
CGImageRef myThumbnailImage = NULL;
CGImageSourceRef myImageSource;
CFDictionaryRef myOptions = NULL;
CFStringRef myKeys[3];
CFTypeRef myValues[3];
CFNumberRef thumbnailSize;
// Create an image source from NSData; no options.
myImageSource = CGImageSourceCreateWithData((CFDataRef)data,
NULL);
// Make sure the image source exists before continuing.
if (myImageSource == NULL){
fprintf(stderr, "Image source is NULL.");
return NULL;
}
// Package the integer as a CFNumber object. Using CFTypes allows you
// to more easily create the options dictionary later.
thumbnailSize = CFNumberCreate(NULL, kCFNumberIntType, &imageSize);
// Set up the thumbnail options.
myKeys[0] = kCGImageSourceCreateThumbnailWithTransform;
myValues[0] = (CFTypeRef)kCFBooleanTrue;
myKeys[1] = kCGImageSourceCreateThumbnailFromImageIfAbsent;
myValues[1] = (CFTypeRef)kCFBooleanTrue;
myKeys[2] = kCGImageSourceThumbnailMaxPixelSize;
myValues[2] = (CFTypeRef)thumbnailSize;
myOptions = CFDictionaryCreate(NULL, (const void **) myKeys,
(const void **) myValues, 2,
&kCFTypeDictionaryKeyCallBacks,
& kCFTypeDictionaryValueCallBacks);
// Create the thumbnail image using the specified options.
myThumbnailImage = CGImageSourceCreateThumbnailAtIndex(myImageSource,
0,
myOptions);
// Release the options dictionary and the image source
// when you no longer need them.
CFRelease(thumbnailSize);
CFRelease(myOptions);
CFRelease(myImageSource);
// Make sure the thumbnail image exists before continuing.
if (myThumbnailImage == NULL){
fprintf(stderr, "Thumbnail image not created from image source.");
return NULL;
}
return myThumbnailImage;
}
3、逐步加载图像
如果您有一张非常大的图像,或者正在通过 Web 加载图像数据,则可能需要创建一个增量图像源,以便在积累图像数据时可以绘制图像数据。
您需要执行以下任务才能从 CFData 对象增量加载图像:
- 创建 CFData 对象用于累积图像数据。
- 通过调用
CGImageSourceCreateIncremental
函数创建增量图像源。 - 将图像数据添加到 CFData 对象。
- 调用
CGImageSourceUpdateData
函数,传递 CFData 对象和一个布尔值(bool
数据类型),该布尔值指定数据参数是否包含整个图像或仅包含部分图像数据。
无论如何,数据参数必须包含截至该点为止累积的所有图像文件数据。 - 如果积累了足够的图像数据,则通过调用
CGImageSourceCreateImageAtIndex
来创建图像,绘制部分图像,然后释放它。 - 通过调用
CGImageSourceGetStatusAtIndex
函数来检查是否拥有图像的所有数据。
如果图像完整,此函数将返回kCGImageStatusComplete
。
如果图像不完整,请重复步骤 3 和 4,直到完整为止。 - 释放增量镜像源。
4、显示图像属性
数码照片带有大量关于图像的信息 — 图像尺寸、分辨率、方向、颜色配置文件、光圈、测光模式、焦距、创建日期、关键字、标题等等。
这些信息对于图像处理和编辑非常有用,但前提是数据在用户界面中公开。
虽然 CGImageSourceCopyPropertiesAtIndex
函数检索与图像源中的图像相关的所有属性的字典,但您需要编写代码来遍历该字典以检索并显示该信息。
在本节中,您将仔细查看 OS X *ImageApp示例代码中的一个例程,这是一个您可以下载并试用的图像显示应用程序。
ImageApp 示例代码的功能之一是图像*信息窗口,该窗口显示当前活动图像的缩略图和图像属性,如图 2-1所示。
图 2-1 显示图像属性的信息窗口
您可以查看ImageInfoPanel.h
和ImageInfoPanel.m
文件以了解此面板的所有实现细节;您还需要查看项目的 nib 文件以了解如何设置窗口和绑定。
要了解如何使用 CGImageSource 函数来支持图像编辑应用程序,请查看例 2-3 。
例后面显示了每行代码的详细说明。
(请记住,这个例程不是独立例程——您不能简单地将其粘贴到您自己的程序中。它是*ImageApp*示例代码的摘录。)
例 2-3 创建图像源并检索属性的例程
- (void) setURL:(NSURL*)url
{
if ([url isEqual:mUrl])
return;
mUrl = url;
CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL); // 1
if (source)
{
NSDictionary* props =
(NSDictionary*) CGImageSourceCopyPropertiesAtIndex(source, 0, NULL); // 2
[mTree setContent:[self propTree:props]]; // 3
NSDictionary* thumbOpts = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailWithTransform,
(id)kCFBooleanTrue, (id)kCGImageSourceCreateThumbnailFromImageIfAbsent,
[NSNumber numberWithInt:128], (id)kCGImageSourceThumbnailMaxPixelSize,
nil]; // 4
CGImageRef image = CGImageSourceCreateThumbnailAtIndex(source, 0,
(CFDictionaryRef)thumbOpts); // 5
[mThumbView setImage:image]; // 6
CGImageRelease(image); // 7
[mFilePath setStringValue:[mUrl path]]; // 8
NSString* uti = (NSString*)CGImageSourceGetType(source); // 9
[mFileType setStringValue:[NSString stringWithFormat:@"%@\n%@",
ImageIOLocalizedString(uti), uti]]; // 10
CFDictionaryRef fileProps = CGImageSourceCopyProperties(source, nil); // 11
[mFileSize setStringValue:[NSString stringWithFormat:@"%@ bytes",
(id)CFDictionaryGetValue(fileProps, kCGImagePropertyFileSize)]]; // 12
}
else // 13
{
[mTree setContent:nil];
[mThumbView setImage:nil];
[mFilePath setStringValue:@""];
[mFileType setStringValue:@""];
[mFileSize setStringValue:@""];
}
}
代码的作用如下:
- 根据传递给例程的 URL 创建图像源对象。
- 复制位于索引位置 处的图像的属性
0
。
某些图像文件格式可以支持多幅图像,但此示例假设只有一幅图像(或者感兴趣的图像始终是文件中的第一幅图像)。
CGImageSourceCopyPropertiesAtIndex
函数返回一个 CFDictionary 对象。
在这里,代码将 CFDictionary 转换为对象NSDictionary
,因为这些数据类型是可互换的(有时称为免费桥接)。
返回的字典包含键值对形式的属性。
但是,有些值本身就是包含属性的字典。
查看图 2-1,您不仅会看到简单的键值对(例如颜色模型-RGB),还会看到 Exif 属性、IPTC 属性、JFIF 属性和 TIFF 属性,每个属性都是一个字典。
单击其中一个的显示三角形将显示该字典中的属性。
您需要获取这些字典及其属性,以便它们可以在信息面板中正确显示。
这就是下一步要完成的任务。 - 从字典中提取属性并将其设置为树控制器。
如果您查看该ImageInfoPanel.h
文件,您会看到该mTree
变量是一个NSTreeController
对象,它是 Interface Builder 中的一个出口。
此控制器管理一个对象树。
在本例中,对象是图像的属性。
ImageInfoPanel.m
文件中提供了propTree:
方法。
其目的是遍历上一步中检索到的属性字典,提取图像属性,并构建与NSTreeController
对象绑定的数组。
属性显示在图 2-1中的键和值表中。 - 设置从图像源创建图像时要使用的选项字典。
回想一下,选项是通过字典传递的。
图 2-1中所示的信息面板显示缩略图。
此处的代码设置了创建缩略图的选项,该缩略图会旋转并缩放到与完整图像相同的方向和纵横比。
如果缩略图尚不存在,则会创建一个,其最大像素大小为 128 x 128 像素。 - 使用上一步中设置的选项,从图像源中的第一个图像创建缩略图。
- 将缩略图设置为信息面板中的视图。
- 释放图像;它不再需要。
- 从传递给该方法的 URL 中提取路径,并将字符串设置为绑定到信息面板的文本字段。
这是图 2-1中的路径文本字段。 - 获取图像源的统一类型标识符。(这可能与源中的图像类型不同。)
- 调用一个函数来检索 UTI 的本地化字符串(
ImageIOLocalizedString
在ImagePanel.m
中声明),然后将该字符串设置为绑定到信息面板的文本字段。
这是 图 2-1中的 Type 文本字段。 - 检索与图片源关联的属性字典。
这些属性适用于容器(例如文件大小),不一定适用于图片源中的单个图片。 - 从上一步获得的图像源字典中检索文件大小值,然后将关联的字符串设置为绑定到信息面板的文本字段。
这就是图 2-1中所示的“大小”文本字段。 - 如果未创建源,请确保用户界面中的所有字段都反映该事实。
四、使用图像目标
图像目标抽象了数据写入任务,无需您通过原始缓冲区管理数据。
图像目标可以表示单个图像或多个图像。
它可以包含缩略图以及每个图像的属性。
为适当的目标(URL、CFData 对象或 Quartz 数据使用者)创建 CGImageDestination 对象后,您可以添加图像数据并设置图像属性。
添加完数据后,调用CGImageDestinationFinalize
函数。
1、设置图像目标的属性
CGImageDestinationSetProperties
函数 将 属性(键值对)字典 ( CFDictionaryRef
) 添加到图像目标中的图像。
虽然设置属性是可选的,但在许多情况下您需要设置它们。
例如,如果您的应用程序允许用户向图像添加关键字或更改饱和度、曝光度或其他值,您需要将该信息保存在选项字典中。
Image I/O 定义了一组广泛的键来指定诸如压缩质量、背景合成颜色、Exif 字典键、颜色模型值、GIF 字典键、尼康和佳能相机键等内容。请参阅*CGImageProperties 参考*。
设置字典时,您有两种选择。
您可以创建一个 CFDictionary 对象,也可以创建一个NSDictionary
对象,然后在将选项字典传递给 CGImageDestinationSetProperties
函数时将其转换为CFDictionaryRef
。(CFDictionary 和 NSDictionary
可以互换,或自由桥接。)
例 3-1CFRelease
显示了一个代码片段,它为三个属性分配键值对,然后创建一个包含这些属性的字典。
因为这是一个代码片段,所以没有显示释放代码创建的 CFNumber 和 CFDictionary 对象所需的调用。
当您编写代码时,当您不再需要这些对象时,您需要调用。
为属性设置键值对时,需要查阅参考文档(请参阅*CGImageDestination 参考和CGImageProperties 参考)以了解值的预期数据类型。
如例 3-1所示,数值通常需要包装在 CFNumber 对象中。
使用 Core Foundation 类型作为字典值时,还可以在创建字典时提供回调常量 — kCFTypeDictionaryKeyCallBacks
和kCFTypeDictionaryValueCallBacks
。(请参阅CFDictionary 参考*。)
例 3-1 设置图像目标的属性
float compression = 1.0; // Lossless compression if available.
int orientation = 4; // Origin is at bottom, left.
CFStringRef myKeys[3];
CFTypeRef myValues[3];
CFDictionaryRef myOptions = NULL;
myKeys[0] = kCGImagePropertyOrientation;
myValues[0] = CFNumberCreate(NULL, kCFNumberIntType, &orientation);
myKeys[1] = kCGImagePropertyHasAlpha;
myValues[1] = kCFBooleanTrue;
myKeys[2] = kCGImageDestinationLossyCompressionQuality;
myValues[2] = CFNumberCreate(NULL, kCFNumberFloatType, &compression);
myOptions = CFDictionaryCreate( NULL, (const void **)myKeys, (const void **)myValues, 3,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
// Release the CFNumber and CFDictionary objects when you no longer need them.
2、将图像写入图像目标
要将图像写入目标,首先需要通过调用 CGImageDestinationCreateWithURL
、CGImageDestinationCreateWithData
或 CGImageDestinationCreateWithDataConsumer
函数来创建图像目标对象。
您需要提供生成的图像文件的UTI。您可以提供 UTI 或等效常量(如果有)。请参阅表 1-1。
创建图像目标后,您可以通过调用CGImageDestinationAddImage
或CGImageDestinationAddImageFromSource
函数向其中添加图像。
如果图像目标文件的格式支持多幅图像,则可以重复添加图像。
调用 CGImageDestinationFinalize
函数会向Image I/O 发出信号,表示您已完成添加图像。
一旦完成,您就无法再向图像目标添加任何数据。
例 3-2显示了如何实现写入图像文件的方法。
虽然此例显示了如何在 Objective-C 方法中使用图像目标,但您也可以在过程 C 函数中轻松创建和使用图像目标。
options 参数包括您想要为图像指定的任何属性,例如相机或压缩设置。
例 3-2 将 图像写入 URL 的方法
- (void) writeCGImage: (CGImageRef) image toURL: (NSURL*) url withType: (CFStringRef) imageType andOptions: (CFDictionaryRef) options
{
CGImageDestinationRef myImageDest = CGImageDestinationCreateWithURL((CFURLRef)url, imageType, 1, nil);
CGImageDestinationAddImage(myImageDest, image, options);
CGImageDestinationFinalize(myImageDest);
CFRelease(myImageDest);
}
3、创建动画图像
Image I/O 还可用于创建动画图像。
创建动画图像时,为要添加到图像的每一帧 需要调用 CGImageDestinationAddImage
。
您还必须指定 控制动画执行方式 的其他属性。
例 3-3显示了 如何创建动画 PNG 图像。
首先,它创建一对字典来保存动画属性。
第一个字典指定 动画 PNG 在停止在最后一帧之前应重复其动画的次数。
第二个字典指定序列中每一帧使用的帧延迟。
创建图像目标后,代码设置目标图像的文件属性,然后逐帧添加帧。
最后,CGImageDestinationFinalize
调用该方法来完成动画 PNG。
例 3-3 创建动画 PNG 文件
let loopCount = 1
let frameCount = 60
var fileProperties = NSMutableDictionary()
fileProperties.setObject(kCGImagePropertyPNGDictionary, forKey: NSDictionary(dictionary: [kCGImagePropertyAPNGLoopCount: frameCount]))
var frameProperties = NSMutableDictionary()
frameProperties.setObject(kCGImagePropertyPNGDictionary, forKey: NSDictionary(dictionary: [kCGImagePropertyAPNGDelayTime: 1.0 / Double(frameCount)]))
guard let destination = CGImageDestinationCreateWithURL(fileURL, kUTTypePNG, frameCount, nil) else {
// Provide error handling here.
}
CGImageDestinationSetProperties(destination, fileProperties.copy() as? NSDictionary)
for i in 0..<frameCount {
autoreleasepool {
let radians = M_PI * 2.0 * Double(i) / Double(frameCount)
guard let image = imageForFrame(size: CGSize(width: 300, height: 300)) else {
return
}
CGImageDestinationAddImage(destination, image, frameProperties)
}
}
if !CGImageDestinationFinalize(destination) {
// Provide error handling here.
}
2024-06-02(日)