一、Image I/O 的使用
Image I/O 框架提供了从CGImageSourceRef读取图片数据和写入图片数据到CGImageDestinationRef的不透明数据类型。可以支持多种图片格式,包括标准的web格式,高动态范围图片和原始的相机数据。其他特性有:Mac平台下最快速的图片编码和解码,增量加载图片的能力,支持图片元数据,有效的缓存
创建图片源和写入目的地的方法有:1. URLs 。在Image I/O框架中,URL可以表示为Core Foundation数据类型 -- CFURLRef
2.Core Foundation对象 -- CFDataRef 和CFMutableDataRef
3.Quartz data consumer (CGDataConsumerRef) 和 data provider (CGDataproviderRef)对象
1、使用方法
在项目中添加:#import <ImageIO/ImageIO.h>
2、支持的图片格式
Image I/O框架支持大多数图片文件的格式,比如JPEG, JPEG2000, RAW, TIFF, BMP和PNG.可以调用的方法:
CGImageSourceCopyTypeIdentifiers 返回统一类型标识符的数组。Image I/O可以用来作为图片来源
CGImageDestinationCopyTypeIdentifier 则返回作为图片写入目的地的数组
可以使用CFShow来将数组打印在debugger中。
Listing 1-1 获取、打印所支持的统一类型标识符
CFArrayRef mySourceTypes = CGImageSourceCopyTypeIdentifiers();
CFShow(mySourceTypes);
CFArrayRef myDestinationTypes = CGImageDestinationCopyTypeIdentifier();
CFShow(myDestinationTypes);
Table 1-1 常用的统一类型标识符及图片内容类型常量
Uniform type identifier -- Image content type constant
public.image -- kUTTypeImage
public.png -- kUTTypePNG
public.jpeg -- kUTTypeJPEG
public.jpeg-2000(只用于OS X) -- kUTTypeJPEG2000
public.tiff -- kUTTypeTIFF
com.apple.pict(只用于OS X) -- kUTTypePICT
com.compuserve.gif -- kUTTypeGIF
二、创建和使用图片源
图片源提取了数据访问任务并且节省了通过原始缓存数据中管理数据的需要。数据源可以包含多个图片,缩略图,每张图片的属性和图片文件。当你需要用到图片数据时,图片源是最好的方式。在差un关键CGImageSource对象后,你可以获取图片,缩略图,图片属性和其他图片信息
1、从图片源创建一张图片
Image I/O最经常完成的一个任务就是从图片源中创建图片。如下面的例子所示。该例子展示了怎样从路径名中创建一个图片源并且抽取图片。当你创建图片源对象后,你可以提供一个图片格式的提示
从图片源中创建图片时,必须指定一个索引并且提供属性的字典来指定是否创建缩略图、是否允许缓存等。详见CGImageSource Reference 和 CGImageProperties Reference
提供索引的原因是因为一些图片文件格式允许同个图片源中有多个图片。如果只有一个的话可以传0。可以调用CGImageSourceGetCount来获取数量
Listing 2-1
CGImageRef MyCreateCGImageFromFile (NSString *path) {
// 获取URL
NSURL *url = [NSURL fileURLWithPath:path];
CGImageRef myImage = NULL;
CGImageSourceRef myImageSource;
CFDicitonaryRef myOptions = NULL;
CFStringRef myKeys[2];
CFTypeRef myValues[2];
// 在需要的时候设置选项。这些选项用于将图片缓存成解码格式并且在图片格式支持浮点值时使用浮点值
myKeys[0] = kCGImageSourceShouldCache;
myValues[0] = (CFTypeRef)kCFBooleanTrue;
myKeys[1] = kCGImageSourceShouldAllowFloat;
myValues[1] = (CFTypeRef)kCFBooleanTrue;
// 创建字典
myOptions = CFDictionaryCreate(NULL, (const void **) myKeys, (const void **)myValues, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBack);
// 给URL创建图片源
myImageSource = CGImageSourceCreateWithURL ((CFURLRef)url, myOptions);
CFRelease(myOptions);
// 在继续之前确保图片源存在
if (myImageSource == NULL) {
fprintf(stderr, "Image source is NULL.");
return NULL;
}
// 创建图片源的第一个项目
myImage = CGImageSourceCreateImageAtIndex(myImageSource, 0, NULL);
CFRelease(myImageSource);
// 确保图片存在
if (myImage == NULL) {
fprintf(stderr, "Image not created from image source");
return NULL;
}
return myImage;
}
2.从图片源创建一张缩略图
有的图片源包含了你可以获取的缩略图。如果缩略图没有呈现出来的话,Image I/O则可以帮助你进行创建。你也可以指定最大的缩略图大小并且确定是否进行转换等操作。
Listing 2-2表明怎样从数据中创建图片源,并设置缩略图相关的属性,再创建缩略图。使用kCGImageSourceCreateThumbnailWithTransform键来设置缩略图是否应该旋转或者放缩来适配方向和像素
Listing 2-2 创建缩略图
CGImageRef MyCreateThumbnnailImageFromData (NSData *data, int imageSize) {
CGImageRef myThumbnailImage = NULL;
CGImageSourceRef myImageSource;
CFDictionaryRef myOptions = NULL;
CFStringRef myKeys[3];
CFTypeRef myValues[3];
CFNumberRef thumbnailSize;
// 从NSData创建图片源
myImageSource = CGImageSourceCreateWithData((CFDataRef)data, NULL);
// 进行下一步之前确保图片源存在
if (myImageSource == NULL) {
fprintf(stderr, "Image source is NULL.");
return NULL;
}
// 将整数打包为CFNumber对象。使用CFTypes会使得创建选项字典更加容易
thumbnailSize = CFNumberCreate(NULL, kCFNumberIntType, &imageSize);
// 设置缩略图选项
myKeys[0] = kCGImageSourceCreateThumbnailWithTransform;
myValues[0] = (CFTypeRef)kCFBooleanTrue;
<pre name="code" class="objc"> myKeys[1] = kCGImageSourceCreateThumbnailFromImageIfAbsent;
myValues[1] = (CFTypeRef)kCFBooleanTrue;
myKeys[2] = kCGImageSourceCreateThumbnailMaxPixelSize; myValues[2] = (CFTypeRef)thumbnailSize;
myOptions = CFDictionaryCreate(NULL, (const void **)myKeys, (const void **)myValues, 2, &kCFTypeDictionaryKeyCallBack, &kCFTypeDictionaryValueCallBacks);
// 使用指定选项创建缩略图
myThumbnailImage = CGImageSourceCreateThumbnailAtIndex(myImageSource, 0, myOptions);
// 在不需要时,释放选项字典和图片源
CFRelease(thumbnailSize);
CFRelease(myOptions);
CFRelease(myImageSource);
// 确保缩略图存在
if (myThumbnailIamge == NULL) {
fprintf(stderr, "Thumbnail image not created from image source");
return NULL;
}
return myThumbnailImage;
}
3.逐步加载图片
如果有一张非常大的图片,或者是从web上加载的图片时,你可以创建一个逐步加载的图片源,以便绘制图片。做法如下:
1.创建累加图片数据的CFData对象
2.调用CGImageSourceICreateIncremental函数来创建增量图片源
3.添加图片数据到CFData对象
4.调用CGImageSourceUpdateData函数,将CFData对象和指定数据参数是否包含整张图片亦或者是部分的图片数据的布尔值传递过去。事实上,数据参数必须包含包含完整的图片文件数据,以便能加载到那个点。
5.如果已经累加完毕,调用CGImageSourceCreateImageAtIndex来创建图片,绘制图片,然后释放之
6.通过CGImageSourceGetStatusAtIndex来检查图片数据是否已经完整了。如果图片数据已经完整,则会返回kCGImageStatusComplete,否则会重复步骤3和4
7.释放增量图片源
三、图像目的地
图片目的地抽象化了数据写入任务并且省去了从缓存器重管理数据的步骤。图像目的地可以呈现一张或多张图片。包含缩略图和每张图片的属性。在创建CGImageDestination对象(URL, CFData或者Quartz数据)后,可以添加图片数据,设置图片属性,完成操作后,调用CGImageDestinationFinalize.
1.设置属性
CGImageDestinationSetProperties添加了属性字典(CFDictionaryRef)。虽然属性的设置是可选的,但是通常都会设置属性来完成自己的需求。举个例子,如果你的程序允许用户添加图片关键字或者改变饱和度,曝光值等,就可将这些值保存在字典中。
Image I/O定义了一系列可扩展的键来指定压缩质量,背景颜色合成的EXIF字典键,颜色模型值,GIF字典键,尼康和佳能相机键,等等。
float compression = 1.0; // 需要时无损压缩
int orientation = 4; // 原来的是左边底部.
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);
// 释放CFNumber和CFDictionary对象.
2.写入图片到目的地
要将图片写入的话,首先需要通过调用CGImageDestinatonCreateWithURL,CGimageDestinationCreateWithData或者CGImageDestinationCreateWithDataConsumer来创建目的地对象。
创建目的地对象后,调用CGImageDestinationAddImage或者CGImageDestinationAddImageFromSource来添加图片。如果图片目的地支持多张图片,则可以重复添加。调用CGImageDestinationFinalize来通知Image I/O图片添加完毕。完成后就不能再添加了。
- (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);
}