Image I/O 编程指南文档笔记 Image I/O Programming Guide
Image I / O编程接口允许应用程序读取和写入大多数图像文件格式。最初是Core Graphics框架的一部分,Image I / O驻留在它自己的框架中,允许开发人员独立于Core Graphics(Quartz 2D)使用它。 Image I / O提供了访问图像数据的明确方式,因为它非常高效,可以轻松访问元数据并提供颜色管理。image IO和 Bitmap images and image masks 绘制文档笔记 的图片绘制相关。
Image I / O框架提供了用于从源(CGImageSourceRef)读取图像数据并将图像数据写入目标(CGImageDestinationRef)的不透明数据类型。它支持多种图像格式,包括标准网页格式,高动态范围图像和原始相机数据。图像I / O具有许多其他功能,例如:
•mac平台上最快的图片解码和编码
•增量加载图片
•支持图片metadata
•效果缓存
你可以创建image source and image destination,通过以下几种方式:
1. URLs. I其位置可以被指定为URL的图像可以充当图像数据的提供者或接收者。在Image I / O中,URL表示为Core Foundation数据类型CFURLRef。
2. The Core Foundation 对象 CFDataRef and CFMutableDataRef.
3. Quartz data consumer (CGDataConsumerRef) and data provider (CGDataProviderRef) objects
应用程序里使用 Image IO
只需要 #import <ImageIO/ImageIO.h
支持的图片格式
几乎支持所有的常见图片格式。比如:JPEG, JPEG2000, RAW, TIFF, BMP, and PNG. 并非所有格式在每个平台上均受支持。有关Image I / O支持的最新列表,可以调用以下功能:
•CGImageSourceCopyTypeIdentifiers 返回一个Uniform Type Identifiers (UTIs) 的数组,image io 作为数据源支持
•CGImageDestinationCopyTypeIdentifiers 返回一个Uniform Type Identifiers (UTIs) 数组,image io 作为图片目标
您可以使用CFShow函数将数组打印到Xcode中的控制台,如图所示。 这些函数返回的数组中的字符串采用com.apple.pict,public.jpeg,public.tiff等形式。 表1-1列出了许多常见图像文件格式的UTI。 OS X和iOS为大多数常见的图像文件格式定义常量; 全套常量在UTCoreTypes.h头文件声明。 当需要指定图像类型时,可以使用这些常量,既可以作为图像源的提示(kCGImageSourceTypeIdentifierHint),也可以作为图像目标的图像类型。
CFArrayRef mySourceTypes = CGImageSourceCopyTypeIdentifiers();
|
CFShow(mySourceTypes);
|
CFArrayRef myDestinationTypes = CGImageDestinationCopyTypeIdentifiers();
|
CFShow(myDestinationTypes);
|
Common uniform type identifiers (UTIs) and image content type constants
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 |
创建和使用一个image source
使用Image I / O框架执行的最常见任务之一是从图像源创建图像,如清单2-1所示。 此示例显示如何从路径名创建图像源,然后提取图像。 在创建图像源对象时,可以提供关于图像源文件格式的提示。
当您从图像源创建图像时,必须指定一个索引,并且可以提供属性字典(键值对),以指定是创建缩略图还是允许缓存等。 CGImageSource Reference和CGImageProperties参考列表键以及每个键的值的预期数据类型。
您需要提供索引值,因为某些图像文件格式允许多个图像驻留在同一个源文件中。 对于只包含一个图像的图像源文件,请传递0.您可以通过调用函数CGImageSourceGetCount来找出图像源文件中的图像数量。
Listing 2-1 Creating an image from an image source
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;
}
从image source创建一个缩略图
某些图像源文件包含可以检索的缩略图图像。 如果缩略图不存在,Image I / O可以让您选择创建它们。 您还可以指定最大缩略图大小以及是否将缩略图图像应用到变形。
清单2-2显示了如何从数据创建图像源,设置包含与缩略图相关的选项的字典,然后创建缩略图图像。 您可以使用kCGImageSourceCreateThumbnailWithTransform键指定缩略图图像是否应旋转和缩放以匹配完整图像的方向和像素宽高比。
Listing 2-2 Creating a thumbnail image
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;
}
增量加载图片 Incrementally Loading an Image
如果您有非常大的图像,或者正在通过网络加载图像数据,则可能需要创建增量图像源,以便在积累图像数据时绘制图像数据。您需要执行以下任务以从CFData对象递增加载图像:
- 创建用于累积图像数据的CFData对象。
- 通过调用函数CGImageSourceCreateIncremental创建增量图像源。
- 将图像数据添加到CFData对象。
- 调用函数CGImageSourceUpdateData,传递CFData对象和一个布尔值(bool数据类型),该值指定数据参数是包含整个图像还是仅包含部分图像数据。在任何情况下,数据参数都必须包含到该点为止累积的所有图像文件数据。
- 如果您已经积累了足够的图像数据,请调用CGImageSourceCreateImageAtIndex创建图像,绘制部分图像,然后释放它。
- 通过调用函数CGImageSourceGetStatusAtIndex来检查是否具有图像的所有数据。如果图像完整,则此函数返回kCGImageStatusComplete。如果图像不完整,请重复步骤3和4直到完成。
- 释放增量图像源。
显示图片的属性
数码照片标有大量关于图像尺寸,分辨率,方向,颜色配置文件,光圈,测光模式,焦距,创建日期,关键字,标题等等的信息。 这些信息对图像处理和编辑非常有用,但只有在用户界面中显示数据时才是如此。 尽管CGImageSourceCopyPropertiesAtIndex函数检索与图像源中图像相关的所有属性的字典,但您需要编写遍历该字典的代码以检索并显示该信息。
使用 image destination
图像目标抽象数据写入任务,并且不需要通过原始缓冲区管理数据。 图像目的地可以表示单个图像或多个图像。 它可以包含缩略图图像以及每个图像的属性。 在为适当的目标(URL,CFData对象或Quartz数据使用者)创建CGImageDestination对象后,可以添加图像数据并设置图像属性。 完成添加数据后,调用函数CGImageDestinationFinalize。
给一个图片目标设置属性
函数CGImageDestinationSetProperties将属性(键值对)的字典(CFDictionaryRef)添加到图像目标中的图像。尽管设置属性是可选的,但您仍有许多情况需要设置它们。例如,如果您的应用程序允许用户为图像添加关键字或更改饱和度,曝光度或其他值,则需要将该信息保存在选项字典中。
Image I / O定义了一系列广泛的键key,用于指定如压缩质量,背景合成颜色,Exif字典按键,颜色模型值,GIF字典key,Nikon和Canon相机key等等。请参阅CGImageProperties参考。
设置词典时,你有两种选择。您可以创建CFDictionary对象,也可以创建NSDictionary对象,然后在将选项字典传递给CGImageDestinationSetProperties函数时将其转换为CFDictionaryRef。 (CFDictionary和NSDictionary是可互换的,toll-free的。)清单3-1显示了一个代码片段,它为三个属性分配键值对,然后创建一个包含这些属性的字典。由于这是一个代码片段,因此不会显示释放由代码创建的CFNumber和CFDictionary对象的必要调用。当你编写你的代码时,当你不再需要这些对象时,你需要调用CFRelease。
为属性设置键/值对时,需要查看参考文档(请参阅CGImageDestination Reference和CGImageProperties Reference)以获取该值的预期数据类型。如清单3-1所示,通常需要将数值包装在CFNumber对象中。在为字典值使用Core Foundation类型时,还可以在创建dictionary-kCFTypeDictionaryKeyCallBacks和kCFTypeDictionaryValueCallBacks时提供回调常量。
Listing 3-1 Setting the properties of an image destination
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.
将图片写入 image destination
要将图像写入目标,首先需要调用CGImageDestinationCreateWithURL,CGImageDestinationCreateWithData或CGImageDestinationCreateWithDataConsumer函数来创建图像目标对象。您需要提供生成的图像文件的UTI。您可以提供UTI或等效常数(如果有的话)。见表1-1。
创建图像目标后,可以通过调用CGImageDestinationAddImage或CGImageDestinationAddImageFromSource函数向其添加图像。如果图像目标文件的格式支持多个图像,则可以重复添加图像。调用函数CGImageDestinationFinalize信号添加图像完成的Image I / O。完成后,您无法将更多数据添加到图像目标。
清单3-2显示了如何实现一个写图像文件的方法。尽管此列表显示了如何从Objective-C方法中使用图像目标,但您可以在类C语言函数中轻松创建和使用图像目标。选项参数包括您要为图像指定的任何属性,例如相机或压缩设置。
Listing 3-2 A method that writes an image to a 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);
|
}
|
创建一个动态图片 Creating an Animated Image
图像I / O也可用于创建动画图像。 在创建动画图像时,您可以为要添加到图像的每个帧调用CGImageDestinationAddImage。 您还必须指定控制动画执行方式的其他属性。
清单3-3显示了如何创建一个动画PNG图像。 首先它创建一对字典来保存动画属性。 第一个字典指定动画PNG应在停止最终帧之前重复动画的时间。 第二个字典指定序列中每个帧使用的帧延迟。 创建图像目标后,代码将设置目标图像的文件属性,然后逐个添加帧。 最后,调用CGImageDestinationFinalize方法来完成动画PNG(aPNG)。
Listing 3-3 Creating an animated PNG file
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.
}
end